如何有效地为多个重复的表保存价值?

时间:2014-10-03 09:01:20

标签: java database oracle performance java.util.concurrent

我有一个名为Message的实体,其字段为:id(PK),String messageXML和Timestamp date。和简单的dao将对象存储到Oracle数据库(11g)/ MyBatis

代码看起来像这样:

SEVICE:

void process throws ProcessException {
Message message = wrapper.getMessage(request);
Long messageId;
try {
messageId = (Long) dao.save(message);
} catch (DaoException e) {
throw ProcessException(e);
}

Dao

private String mapperName = "messageMapper";

Serializable save(Message message) throws DaoException {
try {
     getSqlSession().insert(mapperName + ".insert", message); 
return message.getPrimaryKey();
} catch (Exception e) {
throw DaoException(e);
}

简单的代码。不幸的是,此方法过程(req)的负载大约为500 req / sec。有时我会在保存消息时锁定数据库。

为了解决这个问题我想到了乘法表消息,例如我将有五个表Message1,Message2 ...消息5和保存实体消息我将绘制(如循环算法)表 - 例如:

private Random generator; 

public MessageDao() {
this.generator = new Random();

Serializable save(Message message) throws DaoException {
try {
     getSqlSession().insert(getMapperName() + ".insert", message); 
return message.getPrimaryKey();
} catch (Exception e) {
throw DaoException(e);
}

private String getMapperName() {
return this.mapperName.concat(String.valueOf(generator.nextInt(5))); //could be more effeciency of course
}

您对此解决方案有何看法?可以有效吗?我怎样才能做得更好?我在哪里可以制造瓶颈?

1 个答案:

答案 0 :(得分:1)

在行之间阅读,我猜你有许多代码运行服务多个并发请求的实例,因此你得到了争用的原因。或者你有一台服务器每秒发出500个请求,你会遇到等待。不起诉你的意思。在前一种情况下,您可能希望查看范围分配 - 如果表/索引下一个范围大小很小,您将看到Oracle抓取下一个范围时的定期延迟。大小太小,你会经常得到这种延迟,大小很大,当它最终耗尽时,等待时间会更长。您可以执行类似于每周计算存储的操作,并且每周执行一次相应的“增长”表/索引以在运行时间内避免这种情况。我很想检查统计数据,看看等待的是什么。

但是,如果原因是并发(可能除了扩展管理之外),那么您可能在用于强制执行PK约束的索引上获得热块争用。减轻这种情况的典型策略包括REVERSE索引(无需更改代码),或者更有争议的是使用较弱的唯一约束来使用分区,方法是添加一个简单的列以进一步隔离并发会话。例如。通过此列和现有PK列向表和分区添加列serverId。为每个应用程序服务器分配一个唯一的serverId(config / startup文件)。修改插入以包含serverID。每个服务器有1个分区。有争议的原因是约束较弱(取决于分区的工作方式),这对纯粹主义者来说是一种诅咒,但这是我在Oracle Consulting项目中使用的,以最大限度地提高Exadata的性能。所以,它就在那里。当然,分区可以被认为是分组为超级表的不同表,因此您写入单独表的想法与此处建议的距离不是一百万英里。分区的优势是对这些数据进行分组的更自然的机制,添加新分区所需的工作量比扩展时添加新表要少。