在Java中的MySQL插入语句的性能: 批处理模式准备语句 vs 单个插入语句中的多个值

20 浏览
0 Comments

在Java中的MySQL插入语句的性能: 批处理模式准备语句 vs 单个插入语句中的多个值

我正在设计一个需要处理每秒约600行插入的MySQL数据库,涉及不同的InnoDB表。我目前的实现使用了非批处理的预编译语句。然而,写入MySQL数据库的速度很慢,我的队列大小随时间增长。

这个实现是用Java编写的,我手头不知道版本。它使用了MySQL的Java连接器。我明天需要研究一下是否要切换到JDBC。我假设这两个是不同的连接器包。

我已经阅读了以下关于这个问题的帖子:

- 优化MySQL插入以处理数据流

- MyISAM与InnoDB的比较

- 在不使用预编译语句的情况下向MySQL插入二进制数据

还有MySQL网站上的资料:

- http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html

我的问题是:

- 有人对使用批处理模式下预编译语句的插入与使用单个INSERT语句的多个VALUES之间的性能差异有什么建议或经验吗?

- MySQL Java连接器与JDBC之间的性能差异是什么?我应该使用其中之一吗?

- 这些表是用于存档目的,将会看到大约90%的写入和10%的读取(甚至更少)。我正在使用InnoDB。相对于MyISAM,这是正确的选择吗?

提前感谢您的帮助。

0
0 Comments

MySQL的INSERT语句在Java中的性能:批处理模式预编译语句与单个插入多个值的比较

在使用MySQL的项目中,我们主要使用MyISAM来处理大量的数据,因为它可以在牺牲事务的情况下获得更高的性能。但是一般来说,MyISAM更快但是InnoDB更可靠。

大约一年前,我对INSERT语句的性能也产生了疑问,于是我找到了以下的旧测试代码(抱歉,它有点复杂,超出了您的问题范围)。下面的代码包含了插入测试数据的4种方式:

- 单个INSERT语句;

- 批处理INSERT语句;

- 手动批量INSERT语句(不建议使用,因为它很危险);

- 最后是预编译批量INSERT语句。

代码使用TestNG作为运行器,并使用了一些自定义的代码,例如:

- runWithConnection()方法:在回调执行后确保连接关闭或放回连接池(但是下面的代码使用了不可靠的语句关闭策略,没有使用try/finally来简化代码);

- IUnsafeIn接口:用于接受单个参数但可能抛出类型为E的异常的方法的自定义回调接口,例如void handle(T argument) throws E。

以下是代码示例(省略部分代码):

...

通过对比上述四种方式的性能,可以发现MyISAM的性能要比InnoDB高很多。

希望这可以帮助到您。

更新:

对于第四种方式,您必须在mysql.ini文件中的[mysqld]部分正确设置max_allowed_packet,以支持非常大的数据包。

感谢这些基准测试,这是我最期待的直接的答案。我今天实现了批处理预编译插入,效果非常好!

不知道为什么批处理插入在InnoDB上比单个插入慢?

嗯,是的,很难说,因为这可能只与特定的测试用例有关。谢谢您的注意。

0
0 Comments

问题的原因是在使用MySQL的插入语句时,单个插入多个值的性能不如批处理模式准备好的语句。解决方法是在jdbc url中添加"rewriteBatchedStatements=true"参数,可以显著提高批处理语句的性能。

文章正文:

我知道这个帖子很旧了,但我想提一下,在使用MySQL时,如果在jdbc url中添加"rewriteBatchedStatements=true"参数,可以在使用批处理语句时获得巨大的性能提升。

这是我第一次遇到"rewriteBatchedStatements"设置。对于大批量语句,这将使速度提高数个数量级,正是我一直在寻找的。更多信息请参见stackoverflow.com/questions/26307760

0
0 Comments

MySQL在Java中的插入语句性能:批处理模式准备语句 vs 多值单插入的性能比较

问题的出现原因:是否在受影响的表中有任何触发器?如果没有的话,每秒600次插入并不算多。JDBC的批量插入功能会在同一事务中多次发出相同的语句,而多值SQL会将所有值压缩到单个语句中。在多值语句的情况下,您将不得不动态构造插入SQL,这可能会增加额外的代码、内存、SQL注入保护机制等开销。首先尝试常规的批处理功能,对于您的工作负载,这应该不是一个问题。

问题的解决方法:如果您不以批量方式接收数据,请考虑在插入之前进行批量处理。我们在单独的线程上使用队列来实现生产者-消费者模式。在这种情况下,我们会保留插入,直到经过一定的时间或队列的大小超过阈值。

代码示例:

if(System.currentTimeMillis()-lastInsertTime > TIME_THRESHOLD || queue.size() > SIZE_THRESHOLD) {
    lastInsertTime = System.currentTimeMillis();
    // 插入逻辑
} else {
    // 什么都不做或者等待一段时间后重试
}

感谢您的建议。我今天进行了一些研究,并创建了一个简单的生产者-消费者关系。我的数据处理器在一个线程中工作,将信息添加到属于MySQL插入线程的队列中。看起来效果不错。我使用InnoDB是因为有一些重要的外键关系我想尝试保持。但似乎在整个计划中它们可能并不是必需的,所以我可能明天会切换到MyISAM并看看效果如何。

0