2017-08-21 11 views
1

約更新を試みています。二段階の表に3800行:0 UCanAccessを使用して同じテーブルを使用した後続のクエリのパフォーマンスが低い

    1. セットのすべての値は計算値にループ内でそれらのいくつかを設定

    最初のステップは、高速(< 1S)であります。しかし、2番目のステップは約3秒かかります。たぶんコードに問題があるかもしれません。なぜなら、最初のステップを使わないでコードを実行したり、別のテーブルで最初のクエリを実行したりすると、2番目のステップも非常に高速です(< 0.1秒)。同じテーブルの最初のステップの後に実行されるときだけ遅いです。

    Class.forName("net.ucanaccess.jdbc.UcanaccessDriver"); 
    conn = DriverManager.getConnection("jdbc:ucanaccess://" 
         + path +;singleconnection=true" ,"", ""); 
    
    // First update (reset all values) 
    long start = System.currentTimeMillis();   
    PreparedStatement ps2 = conn.prepareStatement("UPDATE mytab SET val = 0.0;"); 
    ps2.executeUpdate(); 
    ps2.close(); 
    System.out.println("Update 1: " + (System.currentTimeMillis()-start)/1000.0 + " s"); 
    
    // Second update 
    start = System.currentTimeMillis(); 
    conn.setAutoCommit(false); 
    int count = 0; 
    PreparedStatement ps = conn.prepareStatement("UPDATE mytab SET val = ? WHERE id = ?;"); 
    
    for(int j= 1; j <= 3600; j++){ 
         double value; 
         // calculate some value .... 
         value = 1.3; 
         // update table under certain conditions 
         if(true){ 
           ps.setDouble(1, value); 
           ps.setInt(2, j); 
           ps.addBatch(); 
           count++; 
         } 
         if(count > 200){ 
           ps.executeBatch(); 
           count = 0; 
         } 
    } 
    ps.executeBatch(); 
    conn.commit(); 
    System.out.println("Update 2: " + (System.currentTimeMillis()-start)/1000.0 + " s"); 
    

    なぜ、2番目のステップが長くかかるのですか?これを避ける方法は?

    (私はすでに同じ質問をhereにしましたが、成功しませんでした)。

    編集:私は古いJDBC-ODBCブリッジ(とJava 7)との2つのクエリをしようとした場合 は、2番目のクエリは非常に高速(< 1秒)である第一の後に実行。だから私はUCanAccessの問題でなければならないと思う。

  • +0

    代わりに '価値= 1.3;'てみてください'value =((Long)start).doubleValue();'最初にゼロをゼロにしなくても常に行を更新するようにします。同じテストを同じ 'value'で連続して2回実行するなど、行が変更されない場合、テストはデータベースファイルに書き戻されず、2回目の実行がはるかに速く終了するため、テストが欺かれている可能性があります最初のものより.. –

    +0

    ところで、MySQLはこれと何をする必要がありますか? –

    +0

    @GordThompson:Uuuh、真、テストは誤解を招く、ちょうど を実現していない! (Real)のアップデートはいずれの場合も3秒かかる。 これをスピードアップする方法はありますか? JDBC-ODBCはずっと高速です。 – Sophia

    答えて

    1

    として最初のクエリが値をゼロにしたときに2番目のクエリがすべての行を更新するように強制したため、元のテストは欺かれていました。ただし、最初のクエリが省略された場合、2番目のクエリは単に既存のテスト値で行を「更新」していました。行は実際には変更されていないので、データベースファイルにフラッシュされなかったので、2番目のクエリははるかに高速に実行されました。最初のクエリが実行されたかどうかにかかわらず、2番目のクエリによって行が更新されるように強制されたテスト値を調整すると、同じパフォーマンスが発生しました。

    更新のパフォーマンスについては

    、代わりに直接各行を更新するあなたはそれがより速く

    • に一時テーブルを作成して見つけるかもしれない、
    • 、一時テーブルに新しい値を挿入一時テーブルをメインテーブルにマージし、次に
    • 一時テーブルを削除します。

    私はこれを試み、直接、メインテーブルの行ごとの更新に必要な時間の約四分の一で実行しているようだ:

    StopWatch sw = new StopWatch(); 
    sw.start(); 
    try (Statement st = conn.createStatement()) { 
        st.execute("CREATE TABLE zzzTemp (id LONG, val DOUBLE)"); 
    } 
    double newDbl = ((Long) System.currentTimeMillis()).doubleValue(); // test data 
    try (PreparedStatement ps = conn.prepareStatement("INSERT INTO zzzTemp (id, val) VALUES (?,?)")) { 
        for (int i = 1; i <= 3600; i++) { 
         ps.setInt(1, i); 
         ps.setDouble(2, newDbl); 
         ps.addBatch(); 
        } 
        ps.executeBatch(); 
    } 
    System.out.printf("Overall elapsed time: %d ms%n", sw.getTime()); 
    try (Statement st = conn.createStatement()) { 
        st.execute("MERGE INTO mytab m USING zzzTemp z ON m.id = z.id WHEN MATCHED THEN UPDATE SET m.val = z.val"); 
        System.out.printf("Overall elapsed time: %d ms%n", sw.getTime()); 
        st.execute("DROP TABLE zzzTemp"); 
        System.out.printf("Overall elapsed time: %d ms%n", sw.getTime()); 
    } 
    
    +0

    素晴らしいと本当に速く動作します。ありがとうございました! – Sophia

    2

    なぜなら、mysqlからループEXTERNALがあるからです。呼び出しプログラムは同じ準備済みの文を呼び出し続けますが、実際の文が小さい場合でも、呼び出し/実行ごとにオーバーヘッドが大きくなります。

    理想的な解決策は、条件をSQLに移動して(可能であれば)、mysqlに処理させることです。その場合、それは通常、非常に高速です:mysqlは条件のために適切なデータを持っている場合、実際には

    UPDATE mytab SET value=1.3 WHERE <condition>; 
    

    、あなたは、再び(IF文で両者を組み合わせることができ:

    UPDATE mytab SET value=IF(<condition>, 1.3, 0.0) 
    

    - - EDIT --- トランザクションをアクティブにした場合、最初のクエリはすべてのレコードを取り除き、その後の各クエリは既存の(ライブトランザクション)を変更する必要があります。 2つのクエリ

    +0

    これは、同じテーブルの2番目のクエリを回避し、より速く、真実ですが、1。条件がデータベースになく、2番目のクエリがそうである理由を説明しないため、実行したくありません最初のものが先行するとはるかに遅くなります。 – Sophia

    +0

    あなたが電話するたびに ps.setDouble(1、value); ps.setInt(2、j); ps.addBatch(); プログラムはmysqlに接続し、検証し、実行するクエリを識別し、パラメータを使用してクエリを実行し、<前回と同じようにdbを更新し、ステータスをアプリケーションに戻し、ソケットを閉じる必要があります。 他のすべてのステップは、プログラムからmysqlエンジンへのオーバーヘッドです。彼らはすべて時間がかかります。 3000個のアイテムを購入するか、一度に1個のアイテムを購入するために店に3000回行くのは、店に行くのと同じです。購入(実行)には同じ時間がかかります。旅行には時間がかかります –

    +0

    質問を正しく読み直してください。アクティブなトランザクションがある場合、最初のクエリはすべてのレコードを取り除き、その後の各クエリは既存の(ライブトランザクション)を変更する必要があります。 2つのクエリの間にCOMMITを入れてみてください –

    関連する問題