2017-10-13 9 views
1

バッチ処理にデータアクセスコードを記述して、アプリケーションのパフォーマンスを向上させています。PreparedStatementバッチはプレーンテキストと同様に実行されませんステートメント

私は現時点で削除を行っていますが、これは挿入や更新に簡単に適用できます。

私は対処すべき5つのテーブルを持っています。

public void deleteFooList(final int[] fooIds) 
     throws SQLException { 

    Connection connection = dataSource.getConnection(); 

    try { 
     connection.setAutoCommit(false); 
     PreparedStatement childStatement = connection.prepareStatement(
       "DELETE FROM child WHERE fooId = ?"); 
     PreparedStatement otherStatement = connection.prepareStatement(
       "DELETE FROM otherfoo WHERE fooId = ?"); 
     PreparedStatement userStatement = connection.prepareStatement(
       "DELETE FROM userfoo WHERE fooId = ?"); 
     PreparedStatement modStatement = connection.prepareStatement(
       "DELETE FROM modification WHERE fooId = ?"); 
     PreparedStatement fooStatement = connection.prepareStatement(
       "DELETE FROM foo WHERE id = ?"); 
     for (int fooId : fooIds) { 
      childStatement.setInt(1, fooId); 
      otherStatement.setInt(1, fooId); 
      userStatement.setInt(1, fooId); 
      modStatement.setInt(1, fooId); 
      fooStatement.setInt(1, fooId); 
      childStatement.addBatch(); 
      otherStatement.addBatch(); 
      userStatement.addBatch(); 
      modStatement.addBatch(); 
      fooStatement.addBatch(); 
     } 
     executeBatchAndCheckResult(childStatement, fooIds.length); 
     executeBatchAndCheckResult(otherStatement, fooIds.length); 
     executeBatchAndCheckResult(userStatement, fooIds.length); 
     executeBatchAndCheckResult(modStatement, fooIds.length); 
     executeBatchAndCheckResult(fooStatement, fooIds.length); 

     connection.commit(); 
    } catch (SQLException e) { 
     connection.rollback(); 
     throw e; 
    } finally { 
     connection.close(); 
    } 
} 

そして私もこの試みた:完全ではなく、関連性のために含まれ、このヘルパー関数を使用して

public void deleteFooList2(final int[] fooIds) 
    throws SQLException { 
    StringBuilder deleteChildSql = new StringBuilder(
      "DELETE FROM child WHERE fooId IN ("); 
    StringBuilder deleteOtherSql = new StringBuilder(
      "DELETE FROM otherfoo WHERE fooId IN ("); 
    StringBuilder deleteUserSql = new StringBuilder(
      "DELETE FROM userfoo WHERE fooId IN ("); 
    StringBuilder deleteModSql = new StringBuilder(
      "DELETE FROM modification WHERE fooId IN ("); 
    StringBuilder deleteFooSql = new StringBuilder(
      "DELETE FROM foo WHERE id IN ("); 
    Connection connection = childSource.getConnection(); 

    try { 
     connection.setAutoCommit(false); 
     Statement statement = connection.createStatement(); 
     for (int x = 0; x < fooIds.length; x++) { 
      if (x > 0) { 
       deleteChildSql.append(","); 
       deleteOtherSql.append(","); 
       deleteUserSql.append(","); 
       deleteModSql.append(","); 
       deleteFooSql.append(","); 
      } 
      deleteChildSql.append(fooIds[x]); 
      deleteOtherSql.append(fooIds[x]); 
      deleteUserSql.append(fooIds[x]); 
      deleteModSql.append(fooIds[x]); 
      deleteFooSql.append(fooIds[x]); 
     } 
     deleteChildSql.append(")"); 
     deleteOtherSql.append(")"); 
     deleteUserSql.append(")"); 
     deleteModSql.append(")"); 
     deleteFooSql.append(")"); 
     statement.addBatch(deleteChildSql.toString()); 
     statement.addBatch(deleteOtherSql.toString()); 
     statement.addBatch(deleteUserSql.toString()); 
     statement.addBatch(deleteModSql.toString()); 
     statement.addBatch(deleteFooSql.toString()); 
     executeBatchAndCheckResult(statement, fooIds.length); 
     connection.commit(); 
    } catch (SQLException e) { 
     connection.rollback(); 
     throw e; 
    } finally { 
     connection.close(); 
    } 

を:

これらは私が(ヘルパー関数は、一番下にある)しようとした2つの方法があり
private void executeBatchAndCheckResult(Statement statement, 
             int count) 
     throws SQLException { 
    int[] results = statement.executeBatch(); 
    if (results == null) { 
     throw new SQLException(
       "Batch update failed to return results!"); 
    } 
    int total = 0; 
    for (int result : results) { 
     total += result; 
     if (result == Statement.EXECUTE_FAILED) { 
      String sql = statement.toString(); 
      throw new SQLException(String.format(
        "Error executing batch: %s", sql)); 
     } 
    } 
    log.info(String.format("Ran batch, statement count %d, row count %d", 
      results.length, total)); 
    if (results.length != count) { 
     throw new SQLException(String.format(
       "Batch update failed to execute correct count! " + 
         "(%d instead of %d)", results.length, count)); 
    } 
} 

私は、普通のStatementが5 PreparedStatementsよりもずっと速く実行されていることに驚いた。実際、それは見えなかった。 Statementは、単独で5 PreparedStatementsのいずれかと同じくらい速かった。 PreparedStatementバッチを間違って実装していますか?

これはStatementからの高速SQLです:

DELETE FROM foo WHERE id IN (52000,52001,52002,52003,52004,52005,52006,52007,52008,52009,52010) 
DELETE FROM modification WHERE fooId IN (52000,52001,52002,52003,52004,52005,52006,52007,52008,52009,52010) 
DELETE FROM userfoo WHERE fooId IN (52000,52001,52002,52003,52004,52005,52006,52007,52008,52009,52010) 
DELETE FROM otherfoo WHERE fooId IN (52000,52001,52002,52003,52004,52005,52006,52007,52008,52009,52010) 
DELETE FROM childfoo WHERE fooId IN (52000,52001,52002,52003,52004,52005,52006,52007,52008,52009,52010) 

が、これはPreparedStatementsから遅いSQLです:それは正確に何が起こっているかではありませんので、これはP6Spyからである

DELETE FROM foo WHERE id = 52010 
DELETE FROM modification WHERE fooId = 52010 
DELETE FROM userfoo WHERE fooId = 52010 
DELETE FROM otherfoo WHERE fooId = 52010  
DELETE FROM childfoo WHERE fooId = 52010 

PreparedStatementsからのログは、最後にバッチに追加された項目を表示しているだけで、すべてDELETEではありません。

私は上のMySQLのJDBCパラメータrewriteBatchedStatements=trueを持っているので、私は、MySQLのConnector/Jは

DELETE FROM foo WHERE id = 52010 OR id = 52009 OR id = 52008 OR id = 52007 OR id = 52006 OR id = 52005 etc 

のような類似したものにバッチを書き換えているか、多分それはないのか?と仮定していますか私は間違って何をすることができますか?

+2

手動で削除するのではなく、カスケードオプション付きの外部キーを使用する必要があります。 –

+0

はデータベースにありますか? JPAフレームワークについて話していますか?もちろん、データベースには – Adam

+0

があります。 –

答えて

3

私は上のMySQLのJDBCパラメータrewriteBatchedStatements=trueを持っているので、私は、MySQLのConnector/Jが書き換えされていることを想定していたバッチ

[削除]いいえ、そうではありません。 rewriteBatchedStatements=trueは、INSERT INTO ... VALUES ...のバッチでのみ動作します。 DELETE ... WHERE fooId = ?ステートメントのバッチは、各DELETEステートメントを個別に送信します。そのため、PreparedStatementバッチとStatement(1回のラウンドトリップで複数の行を削除するよう手動で最適化されている)とのパフォーマンスの違いがわかります。

+0

クライアント側の準備がサーバー側ではなく、デフォルトである可能性がありますか? –

+0

@MangatRaiModi - クイックテストではないことが示唆されています。 'useServerPreparedStmts = true'は' rewriteBatchedStatements = true'の嫌悪感を変えずにDELETE文のバッチを書き直します。それらは依然として個別に送信されます。 –

+0

ありがとう、私は会話について尋ねていた。 useServerPreparedStmts = false、送信されたステートメント(削除、挿入など)に常につながります。クライアントサイドで解析が行われていますか? –

関連する問題