2012-07-26 73 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