MySQL Insert语句在Java中的性能:批处理模式准备语句与具有多个值的单次插入

MySQL Insert语句在Java中的性能:批处理模式准备语句与具有多个值的单次插入,java,mysql,jdbc,Java,Mysql,Jdbc,我正在设计一个MySQL数据库,它需要每秒处理大约600行插入到各种InnoDB表中。我当前的实现使用非批处理的预处理语句。但是,写入MySQL数据库会出现瓶颈,我的队列大小会随着时间的推移而增加 这个实现是用Java编写的,我现在还不知道它的版本。它使用MySQL的。我需要考虑明天切换到JDBC。我假设这是两个不同的连接器包 我已经阅读了关于这个问题的以下文章: 从mysql站点: 我的问题是: 是否有人对在批处理模式下使用带准备语句的INSERT与使用带多个值的单个INSE

我正在设计一个
MySQL
数据库,它需要每秒处理大约600行插入到各种InnoDB表中。我当前的实现使用非批处理的预处理语句。但是,写入
MySQL
数据库会出现瓶颈,我的队列大小会随着时间的推移而增加

这个实现是用Java编写的,我现在还不知道它的版本。它使用MySQL的
。我需要考虑明天切换到
JDBC
。我假设这是两个不同的连接器包

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

从mysql站点:

我的问题是:

  • 是否有人对在批处理模式下使用带准备语句的INSERT与使用带多个值的单个
    INSERT
    语句的性能差异有过建议或经验

  • MySQL
    Java连接器与
    JDBC
    之间的性能差异是什么。我应该用一个还是另一个

  • 这些表用于存档目的,将看到约90%的写入到约10%的读取(甚至更少)。我正在使用InnoDB。比起MyISAM,这是正确的选择吗


提前感谢您的帮助。

在任何受影响的表上都有触发器吗?如果不是,每秒600次插入看起来并不多

JDBC的批插入功能将在同一事务中多次发出同一语句,而多值SQL将在单个语句中压缩所有值。在使用多值语句的情况下,您必须动态地构造insert SQL,这可能会带来更多代码、更多内存、SQL注入保护机制等方面的开销。首先尝试常规批处理功能,对于您的工作负载来说,这应该不是问题

如果你没有分批接收数据,那么考虑在插入之前进行批量处理。 我们在单独的线程上使用队列来实现生产者-消费者安排。在这种情况下,我们将保留插入,直到经过特定时间或队列大小超过阈值

如果希望生产商收到插入成功的通知,则需要更多的管道

有时,仅仅在线程上阻塞就可以更直接、更实用

if(System.currentTimeMills()-lastInsertTime>TIME_THRESHOLD || queue.size()>SIZE_THRESHOLD) {
    lastInsertTime=System.currentTimeMills();
    // Insert logic
    } else {
    // Do nothing OR sleep for some time OR retry after some time. 
    }

JDBC只是一个JavaSE数据库访问标准,提供标准接口,因此您实际上不必绑定到特定的JDBC实现。MySQL Java连接器(connector/J)是仅用于MySQL数据库的JDBC接口的实现。根据经验,我参与了一个使用MySQL使用大量数据的项目,对于可以生成的数据,我们更喜欢MyISAM:它允许实现更高的性能损失事务,但一般来说,MyISAM更快,但InnoDB更可靠

大约一年前,我也对INSERT语句的性能感到好奇,在我的代码架中发现了以下旧的测试代码(对不起,它有点复杂,超出了您的问题范围)。下面的代码包含插入测试数据的4种方法的示例:

  • 单个
    INSERT
    s
  • 批量
    INSERT
    s
  • 手动批量
    插入
    (切勿使用,否则会有危险)
  • 最后准备了批量
    插入
它用作运行程序,并使用一些自定义遗留代码,如:

  • runWithConnection()
    方法-确保在执行回调后关闭连接或将连接放回连接池(但下面的代码使用不可靠的语句关闭策略-即使没有
    try
    /
    最终减少代码)
    
  • IUnsafeIn
    -用于接受单个参数但可能引发类型E异常的方法的自定义回调接口,如:
    void handle(T参数)引发E
封装测试;
进口试验。IUnsafeIn;
导入java.sql.Connection;
导入java.sql.PreparedStatement;
导入java.sql.SQLException;
导入静态java.lang.String.format;
导入静态java.lang.String.valueOf;
导入静态java.lang.System.currentTimeMillis;
导入core.SqlBaseTest;
导入org.testng.annotations.AfterSuite;
导入org.testng.annotations.BeforeSuite;
导入org.testng.annotations.BeforeTest;
导入org.testng.annotations.Test;
公共最终类InsertVsBatchInsertTest扩展了SqlBaseTest{
私有静态最终整数迭代计数=3000;
私有静态最终字符串CREATE_TABLE_QUERY=“CREATE TABLE IF NOT EXISTS ttt1(c1整数,c2浮点,c3 VARCHAR(5))ENGINE=InnoDB”;
私有静态最终字符串DROP\u TABLE\u QUERY=“DROP TABLE ttt1”;
私有静态最终字符串CLEAR\u TABLE\u QUERY=“从ttt1删除”;
私有静态void withinTimer(字符串名,Runnable){
最终长启动=currentTimeMillis();
runnable.run();
logStdOutF(“%20s:%d ms”,名称,currentTimeMillis()-start);
}
@套房前
公共void createTable(){
runWithConnection(新的IUnsafeIn(){
@凌驾
公共无效句柄(连接)引发SQLException{
final PreparedStatement=connection.prepareStatement(创建表查询);
语句。execute();
语句。close();
}
});
}
@事后
公共void dropTable(){
runWithConnection(新的IUnsafeIn(){
@凌驾
公共无效句柄(连接)引发SQLException{
最终的PreparedStatement语句=connection.prepareStatement(DROP\u TABLE\u QUERY);
语句。execute();
语句。close();
}
});
}
@以前
InnoDB
Single inserts: 74148 ms
Batch insert: 84370 ms
Dirty bulk insert: 178 ms
Safe bulk insert: 118 ms
MyISAM
Single inserts: 604 ms
Batch insert: 447 ms
Dirty bulk insert: 63 ms
Safe bulk insert: 26 ms