2012-07-26 75 views
0

我看到,当从JDBC调用时或者在mysql命令行上调用JDBC时,通过JDBC调用时,mysql插入时间执行的速度要慢几个数量级,并且想知道是否有人可以指向我正确的方向。Mysql缓慢地通过Java插入存储过程JDBC

我在本地运行所有东西,所以网络延迟不应该成为问题。

我创建了以下非常人为的例子来说明这一点。

我创建的存储过程发生在一个单一的INT并将其插入到一个表:

DELIMITER $$ 

CREATE PROCEDURE testInsert(IN input INT) 
BEGIN 
     INSERT INTO test_table(column_1, column_2) 
     VALUES(input, input); 

    END$$ 

DELIMITER ; 

如果我调用命令行或一个MySQL IDE(我使用SQLyog的)此过程:

CALL testInsert(0); 

过程调用时,对于所有意图和目的,立即:

Execution Time : 0.007 sec 
Transfer Time : 0.001 sec 
Total Time  : 0.009 sec 

然而,如果上午从Java调用的程序,使用下面的代码:

public void testStoredProcedureInsert() throws SQLException{ 
    //custom class for managing the sql and variables on the prepared statement 
    SQLStatementBinder sqlBinder = new SQLStatementBinder(); 
    sqlBinder.appendSql("CALL testInsert(?)"); 

    //will store the object into a collection in the sql binder 
    sqlBinder.addBindVariable(0); 

    Class.forName("com.mysql.jdbc.Driver").newInstance(); 

    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/dbname", "user", "pass"); 

    CallableStatement stmt = connection.prepareCall(sqlBinder.getSQL()); 

    //bindSql loops through bind variables and sets the appropriate parameters based on the type of the objects - in this case only preparedStatement.setInt(1, 0) is called. 
    stmt = (CallableStatement)sqlBinder.bindSql(stmt); 

    long start = System.currentTimeMillis(); 

    stmt.executeQuery(); 

    long end = System.currentTimeMillis(); 

    System.out.println("time to call procedure - " + (end-start) + "ms"); 
} 

更新的运行时(注意,我只定时实际执行,以便连接开销,等不被考虑)平均值约为70ms

为了进一步说明这一点,如果我把几个插入一行到存储过程:

DELIMITER $$ 

CREATE PROCEDURE testInsert(IN input INT) 
BEGIN 
     INSERT INTO test_table(column_1, column_2) 
     VALUES(input, input); 

     INSERT INTO test_table(column_1, column_2) 
     VALUES(input, input); 

     INSERT INTO test_table(column_1, column_2) 
     VALUES(input, input); 

     INSERT INTO test_table(column_1, column_2) 
     VALUES(input, input); 

     INSERT INTO test_table(column_1, column_2) 
     VALUES(input, input); 

    END$$ 

DELIMITER ; 

从SQLyog的呼唤还是相当快:

Execution Time : 0.040 sec 
Transfer Time : 0.003 sec 
Total Time  : 0.044 sec 
--------------------------------------------------- 

调用相同的Java代码每个程序呼叫的平均值为225ms

我希望有一些微不足道的事情我做错了,但我愿意接受任何建议或我应该测试的东西。或者从java调用时是否有额外的开销?

对不起有点长的帖子,但我试图提供大量的信息。谢谢你的帮助!

更新只是一个附加的情况下,如果我搬到五个镶入一行:

DELIMITER $$ 

    CREATE PROCEDURE testInsert(IN input INT) 
    BEGIN 
      INSERT INTO test_table(column_1, column_2) 
      VALUES(input, input),(input, input),(input, input),(input, input),(input, input); 

     END$$ 

    DELIMITER ; 

Java运行时均80毫秒这表明过程中的每个单独的声明似乎有从Java调用时会产生额外的开销。

调用没有插入的其他过程,即使那些更复杂并返回几个不同结果集的过程所花的时间也比一些简单插入要少得多。只有选择的过程会很快返回,但是在过程中添加一个插入,运行时比预期的要慢得多(再次,只是从java - 而不是从SQLyog)。

回答

0

好的 - 几个小时后,我随机决定尝试将表上的引擎从InnoDB更改为MyISAM,这似乎显着加速了插入。

猜测我不得不对两个引擎之间的差异做更多的评论,除了MyISAM中缺少FK和事务。

至少它是进步。

1

尝试使用JDBC连接池,并检查时间戳 - 它应该更低(尽管与MySQL插入不一样)。 还要检查用于插入到MySQL中的数据类型以及是否可以以某种方式进行优化。

+0

连接池是否会对单次调用产生重大影响?你有一个首选的连接池库或一些很好的例子吗? – 2012-07-26 04:02:34

+0

是的,它可以 - 你应该比较在正常和重负载下获得连接之前和之后的时间戳。根据配置池的使用方式以及使用它,随着负载的增加,使用连接池应该会更好。对于一个参考,您可以查看用于tomcat的连接池和代码(http://tomcat.apache.org/tomcat-7.0-doc/jndi-datasource-examples-howto.html) - 还有很多其他选项可用(如果您使用的是应用程序服务器/ servlet容器 - 大多数都带有连接池) – 2012-07-26 04:44:31

+0

@MrZorn阅读[Connection Pooling]会很好(http://java.sun.com/developer/onlineTraining/Programming/ JDCBook/conpool.html)。从第一条语句引用:“如果您使用SQL或其他类似工具连接到数据库并对数据执行操作,则可能知道获取连接和登录是需要最多时间的部分。每次需要建立连接时花费几秒钟......如果您使用的是2.0之前的JDBC版本,并且想要提高性能,则可以缓存JDBC连接。“ – 2012-07-26 04:59:20