我最近编写了一个简单的Java程序,它处理了一些数据并将其插入到MyISAM表中。必须插入大约35000行。我使用INSERT ... SET语法编写了INSERT语句,并为PreparedStatement.executeBatch()
的所有行执行了它。所以:
String sql = "INSERT INTO my_table"
+ " SET "
+ " my_column_1 = ? "
+ " my_column_2 = ? "
...
+ " my_column_n = ? ";
try(PreparedStatement pst = con.prepareStatement(sql)){
for(Object o : someCollection){
pst.setInt(1, ...);
pst.setInt(2, ...);
...
pst.setInt(n, ...);
pst.addBatch();
}
pst.executeBatch();
}
我尝试在一个批处理中插入所有行,并且在1000的bacthes中插入,但在所有情况下执行都非常慢(每1000行约1分钟)。经过一些修补后,我发现将语法改为INSERT ... VALUES可以大大提高速度,至少100倍(我没有准确测量它)。
String sql = "INSERT INTO my_table (my_column_1, my_column_2, ... , my_column_n)"
+ " VALUES (?, ?, ... , ?)";
这里发生了什么?使用INSERT ... SET时,JDBC驱动程序是否无法重写批处理?我没有找到任何关于此的文档。我正在使用选项rewriteBatchedStatements=true&useServerPrepStmts=false
创建我的连接。
我在访问另一台主机中的数据库时首先注意到了这个问题。也就是说,我之前使用过INSERT ... SET方法,而在与数据库在同一主机中执行的应用程序中没有任何明显的性能问题。所以我想问题可能是通过INSERT ... SET在网络上发送的语句多于INSERT ... VALUES。
答案 0 :(得分:1)
如果检查INSERT ... SET语法,您将看到它仅用于插入单行。 INSERT ... VALUES用于一次插入多行。
换句话说 - 即使你设置rewriteBatchedStatements = true,JDBC驱动程序也不能像VALUES变量一样优化SET变量,因为SET不是为你的批处理案例构建的。使用VALUES将N个插入压缩为一个。
奖金提示 - 如果您使用ON DUPLICATE KEY UPDATE,则JDBC当前也无法重写这些语句。(编辑:此语句为false - 我的错误。)
你可以设置一个选项来自己验证所有这些(我认为它是'profileSQL')。