2016-11-23 19 views
0

私はサーバxサーバyにあるMySQLデータベースを持っています。選択クエリから取得したMySQL結果セットの挿入?

私はテーブルにそれらをサーバX上に配置されtestxと呼ばれるテーブルからレコードを取得しようと、INSERTだがtestyと呼ばれます。だから、私がしたことはSELECTの声明を実行し、それをresultsetに保存しました。次に、ステートメントをループresultsetwhileループ内で繰り返し実行しようとしています。

private static void cloneTableAndAlter() throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException, InterruptedException { 
     Connection connForSource = getConnectionForSource(); 
     Connection connForTarget = getConnectionForTarget(); 

     if (connForSource != null && connForTarget != null) { 
      try { 
       Statement st = connForSource.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, 
         java.sql.ResultSet.CONCUR_READ_ONLY); 

       String selectStatement = "SELECT field1, field2 FROM dbx.testx where time between ('2016-09-01 00:00:00') and ('2016-09-03 23:59:59');"; 

       String insertStatement = "INSERT INTO testy(" + "field1," + "field2)" + 
         "VALUES(?,?) " + 
         "ON DUPLICATE KEY UPDATE field1 = VALUES(field1);"; <----field1 is a unique key but not primary 

       st.setFetchSize(Integer.MIN_VALUE); 

       ResultSet resultSetForSelect = st.executeQuery(selectStatement); 
       PreparedStatement preparedStatement = connForTarget.prepareStatement(insertStatement); 
       int count = 0; 
       while (resultSetForSelect.next()) { 
        ++count; 
        TableDetails tableDetails = setTableDetails(resultSetForSelect); <--- i'm getting the value from the resultset and setting it to my DTO class. 
        getTableDetails(preparedStatement, tableDetails); <--- setting the values back during the insert from the DTO 
        preparedStatement.executeUpdate(); 
        System.out.println(count + "rows affected"); 
       } 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

:ソーステーブル(testx)以上万レコードを持っているこれは私のサンプルコードです。

私は挿入を行うことができますが、私は挿入がちょっと遅く、毎秒45-50の挿入を得ているように感じます。どこが遅れますか?

この操作を最適化して挿入を増やす方法はありますか、それとも大きなデータセットを挿入するという性質ですか。

ご協力いただければ幸いです。あなたは他の方法で行うことができます

+1

私は時間を要するものを測定することから始めたいです。それは読まれているのか、書かれているのか、あるいはその両方です。読み込みが遅い場合は、時間列にインデックスが必要なことがあります。書き込みが遅い場合、一度に1つの挿入を行うのではなく、バッチ処理を使用して挿入のバッチを送信することができます。両方の場合、おそらくネットワークが問題です。 –

+0

ありがとう@JBNizet、注目。 「時間欄にインデックスだけを必要とする」とはどういう意味ですか? – Kulasangar

+1

qqueryは、rwo値の間に時間があるtestxテーブルの行を探します。その時間列にデータベース索引が定義されていない場合は、MySQLが探している行を見つけるために全表スキャンを実行します。インデックスが定義されている場合、そのインデックスを使用して行をより早く見つけることができます。 –

答えて

0

はこれで選択を作成します。結果は次のようになり

select GROUP_CONCAT(
    CONCAT(" ('",field1,"','",field2,"')")) as vals 
from my_table; 

をConcats:

結果

mysql> select GROUP_CONCAT(
    -> CONCAT(" ('",field1,"','",field2,"')")) as vals 
    -> from my_table; 
+---------------------------------------------------------------------------------------------------------+ 
| vals                         | 
+---------------------------------------------------------------------------------------------------------+ 
| ('O1','AC'), ('O1','PT'), ('O2','PT'), ('O3','MI'), ('O3','PT'), ('O4','EG'), ('O4','PT'), ('O5','PT') | 
+---------------------------------------------------------------------------------------------------------+ 
1 row in set (0,00 sec) 

mysql> 

を使用すると、insertステートメントでこれを連結することができ、1行だけを読み込み、1つのステートメントを書き込み、実行するだけです。

あなたのコード

String selectStatement = "SELECT GROUP_CONCAT(CONCAT(" ('",field1,"','",field2,"')")) as vals 
     FROM dbx.testx where time between ('2016-09-01 00:00:00') and ('2016-09-03 23:59:59');"; 

    ResultSet resultSetForSelect = st.executeQuery(selectStatement); 


    String insertStatement = "INSERT INTO testy(" + "field1," + "field2)" + 
          + String from result + 
          "ON DUPLICATE KEY UPDATE field1 = VALUES(field1);"; <----field1 is a unique key but not primary 


# execute one time 
+1

挿入する行が何千もある場合、文字列は非常に大きくなりすぎます。また、クエリも同様になります。言い換えれば、値のいずれかに単一引用符が含まれている場合、そのクエリは無効になります。 –

+1

しかし、これが主な問題です。あなたは多くのコールを挿入する必要があります。それらを減らす。一度に16または32を取得し、この数の値のペアを持つ2番目に準備されたステートメントを生成する –

関連する問題