我正在设计一个MySQL
数据库,该数据库每秒需要处理各种InnoDB表大约600行的插入。我当前的实现使用非批处理的预处理语句。但是,MySQL
随着时间的推移,写入数据库瓶颈和队列大小会增加。
该实现是用Java编写的,我不知道它的版本。它使用MySQL
的Java连接器。我需要考虑改用JDBC
明天。我假设这是两个不同的连接器包。
我已阅读有关该问题的以下主题:
并从mysql网站:
我的问题是:
有没有人对以批处理方式使用带准备语句的INSERT与使用INSERT
带多个VALUE 的单个语句的性能差异有任何建议或经验。
什么是之间的性能差异MySQL
的Java连接器对JDBC
。我应该使用另一个吗?
这些表用于存档目的,将看到〜90%的写入量到〜10%的读取量(甚至更少)。我正在使用InnoDB。这是MyISAM的正确选择吗?
预先感谢您的帮助。
JDBC只是数据库访问的Java SE标准,提供了标准接口,因此您实际上并不局限于特定的JDBC实现。MySQL Java连接器(Connector /
J)仅是MySQL数据库的JDBC接口的实现。根据经验,我参与了一个使用MySQL使用大量数据的项目,对于可生成的数据,我们最喜欢使用MyISAM:它可以实现更高的性能损失交易,但总的来说,MyISAM更快,但是InnoDB更可靠。
我也想知道大约一年前INSERT语句的性能,并且在我的代码架中找到了以下旧测试代码(对不起,它有点复杂,而且超出了您的问题范围)。以下代码包含4种插入测试数据的方式的示例:
INSERT
s;INSERT
的INSERT
(切勿使用-危险);INSERT
)。它使用TestNG作为运行程序,并使用一些自定义代码,例如:
runWithConnection()
方法-确保在执行回调后连接被关闭或放回连接池(但低于用途声明关闭不可靠的战略的代码-即使没有try
/ finally
减少代码);IUnsafeIn<T, E extends Throwable>
-一个自定义的回调接口,用于接受单个参数但可能会引发E类型异常的方法,例如: void handle(T argument) throws E;
。
package test;
import test.IUnsafeIn;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import static java.lang.String.format;
import static java.lang.String.valueOf;
import static java.lang.System.currentTimeMillis;
import core.SqlBaseTest;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public final class InsertVsBatchInsertTest extends SqlBaseTest {
private static final int ITERATION_COUNT = 3000;
private static final String CREATE_TABLE_QUERY = "CREATE TABLE IF NOT EXISTS ttt1 (c1 INTEGER, c2 FLOAT, c3 VARCHAR(5)) ENGINE = InnoDB";
private static final String DROP_TABLE_QUERY = "DROP TABLE ttt1";
private static final String CLEAR_TABLE_QUERY = "DELETE FROM ttt1";
private static void withinTimer(String name, Runnable runnable) {
final long start = currentTimeMillis();
runnable.run();
logStdOutF("%20s: %d ms", name, currentTimeMillis() - start);
}
@BeforeSuite
public void createTable() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
@Override
public void handle(Connection connection) throws SQLException {
final PreparedStatement statement = connection.prepareStatement(CREATE_TABLE_QUERY);
statement.execute();
statement.close();
}
});
}
@AfterSuite
public void dropTable() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
@Override
public void handle(Connection connection) throws SQLException {
final PreparedStatement statement = connection.prepareStatement(DROP_TABLE_QUERY);
statement.execute();
statement.close();
}
});
}
@BeforeTest
public void clearTestTable() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
@Override
public void handle(Connection connection) throws SQLException {
final PreparedStatement statement = connection.prepareStatement(CLEAR_TABLE_QUERY);
statement.execute();
statement.close();
}
});
}
@Test
public void run1SingleInserts() {
withinTimer("Single inserts", new Runnable() {
@Override
public void run() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
@Override
public void handle(Connection connection) throws SQLException {
for ( int i = 0; i < ITERATION_COUNT; i++ ) {
final PreparedStatement statement = connection.prepareStatement("INSERT INTO ttt1 (c1, c2, c3) VALUES (?, ?, ?)");
statement.setInt(1, i);
statement.setFloat(2, i);
statement.setString(3, valueOf(i));
statement.execute();
statement.close();
}
}
});
}
});
}
@Test
public void run2BatchInsert() {
withinTimer("Batch insert", new Runnable() {
@Override
public void run() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
@Override
public void handle(Connection connection) throws SQLException {
final PreparedStatement statement = connection.prepareStatement("INSERT INTO ttt1 (c1, c2, c3) VALUES (?, ?, ?)");
for ( int i = 0; i < ITERATION_COUNT; i++ ) {
statement.setInt(1, i);
statement.setFloat(2, i);
statement.setString(3, valueOf(i));
statement.addBatch();
}
statement.executeBatch();
statement.close();
}
});
}
});
}
@Test
public void run3DirtyBulkInsert() {
withinTimer("Dirty bulk insert", new Runnable() {
@Override
public void run() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
@Override
public void handle(Connection connection) throws SQLException {
final StringBuilder builder = new StringBuilder("INSERT INTO ttt1 (c1, c2, c3) VALUES ");
for ( int i = 0; i < ITERATION_COUNT; i++ ) {
if ( i != 0 ) {
builder.append(",");
}
builder.append(format("(%s, %s, '%s')", i, i, i));
}
final String query = builder.toString();
final PreparedStatement statement = connection.prepareStatement(query);
statement.execute();
statement.close();
}
});
}
});
}
@Test
public void run4SafeBulkInsert() {
withinTimer("Safe bulk insert", new Runnable() {
@Override
public void run() {
runWithConnection(new IUnsafeIn<Connection, SQLException>() {
private String getInsertPlaceholders(int placeholderCount) {
final StringBuilder builder = new StringBuilder("(");
for ( int i = 0; i < placeholderCount; i++ ) {
if ( i != 0 ) {
builder.append(",");
}
builder.append("?");
}
return builder.append(")").toString();
}
@SuppressWarnings("AssignmentToForLoopParameter")
@Override
public void handle(Connection connection) throws SQLException {
final int columnCount = 3;
final StringBuilder builder = new StringBuilder("INSERT INTO ttt1 (c1, c2, c3) VALUES ");
final String placeholders = getInsertPlaceholders(columnCount);
for ( int i = 0; i < ITERATION_COUNT; i++ ) {
if ( i != 0 ) {
builder.append(",");
}
builder.append(placeholders);
}
final int maxParameterIndex = ITERATION_COUNT * columnCount;
final String query = builder.toString();
final PreparedStatement statement = connection.prepareStatement(query);
int valueIndex = 0;
for ( int parameterIndex = 1; parameterIndex <= maxParameterIndex; valueIndex++ ) {
statement.setObject(parameterIndex++, valueIndex);
statement.setObject(parameterIndex++, valueIndex);
statement.setObject(parameterIndex++, valueIndex);
}
statement.execute();
statement.close();
}
});
}
});
}
}
看一下用@Test注释注释的方法:它们实际上执行INSERT
语句。还请看一看CREATE_TABLE_QUERY
常量:在源代码中,它使用InnoDB在装有MySQL
5.5(MySQL Connector / J 5.1.12)的计算机上产生以下结果:
InnoDB
Single inserts: 74148 ms
Batch insert: 84370 ms
Dirty bulk insert: 178 ms
Safe bulk insert: 118 ms
如果将CREATE_TABLE_QUERY
InnoDB 更改为MyISAM,则会看到显着的性能提升:
MyISAM
Single inserts: 604 ms
Batch insert: 447 ms
Dirty bulk insert: 63 ms
Safe bulk insert: 26 ms
希望这可以帮助。
UPD:
对于第四种方法,您必须适当地自定义max_allowed_packet
in
mysql.ini
(本[mysqld]
节),使其足够大以支持真正的大数据包。
问题内容: 使用JDBC(Oracle),我需要在两个表的每一个中插入大约一千行。像这样: 问题在于两个表都是通过公共序列连接的,因此语句的顺序很重要。 如果我只有一张桌子,那会很容易。在这种情况下,我使用了代码: 但是,这种方法只能用一个准备好的语句,因此只能用一个插入。我该如何解决这个问题? 问题答案: 你可以试试 然后
我想知道是否可以使用一个准备好的语句插入多行。下面是我通常如何在DB中插入一行的示例: 我要插入的值将来自一个数组,例如:$values[0]['val1'];$values[0]["val2“];$values[0]['val3'];$values[1]['val1'];$values[2]['val2']; 等等。 这段代码可能需要一次插入几百行,我想过创建一个循环来创建数百个参数,然后为每一
我有一个脚本可以插入大量的数据。此数据主要是前一个insert的复制,但至少有一个值不同。因此,我准备语句并绑定参数以执行和重复。 我现在使用的代码(一次全部大容量插入): 我想要实现的是,数据将用像上面这样的准备好的语句插入,但每个批处理的限制是1000(或任何其他数字)。我不能让这件事发生。我尝试使用和其他方法,但无法使其工作。
问题内容: 我正在向数据库中插入多行,并将它们连接在一起以提高性能。我收到一个ODBCException告诉我我的SQL语法错误。但是,当我在mysql命令行客户端中尝试它时,它就可以正常工作。我运行了一个简化的测试来描述该过程。 命令行客户端: 之后,我在同一数据库上运行了此代码: 这给了我以下错误: 问题答案: 是的,ODBC不支持批处理。 (编辑:有关最新解决方案,请参见@ Jean-Do的
问题内容: 引用MySQL INSERT手册-UPDATE也一样: 使用关键字DEFAULT可以将列明确设置为其默认值。这使编写INSERT语句(为少数几个列分配值)更加容易,因为它使您避免编写不完整的VALUES列表,该列表不包含表中每个列的值。否则,您将不得不写出与VALUES列表中的每个值相对应的列名列表。 简而言之,如果我写 插入新的一列,并将column2设置为其默认值(无论它是多少)。
问题内容: 我试图用大约50,000行10列填充Java中的resultSet,然后使用的方法将它们插入到另一个表中。 为了使过程更快,我进行了一些研究,发现在将数据读入resultSet时,fetchSize起着重要的作用。 如果fetchSize太低,可能会导致到服务器的行程过多,而fetchSize太高则会阻塞网络资源,因此我做了一些尝试,并设置了适合我的基础结构的最佳大小。 我正在阅读此r