2016-11-23 83 views
0

我有一個MySQL數據庫位於服務器x和另一個在服務器y插入從select查詢中檢索到的MySQL結果集?

我試圖讓從表中的記錄叫testx這是位於服務器X和INSERT他們到一個表名爲暴躁。所以我所做的是執行SELECT聲明並將其存儲到resultset。然後我試圖在resultsetwhile循環內迭代INSERT語句。這是我的示例代碼:

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

我想通過測量什麼需要時間啓動。它是讀取還是寫入,還是兩者兼而有之。如果讀取速度很慢,也許你只需要在時間欄上有一個索引。如果寫入速度較慢,則可以使用批處理來發送批次插入,而不是一次只進行一次插入。如果兩者都存在,也許網絡就是問題所在。 –

+0

謝謝@JBNizet,注意。 「只需要時間列上的索引」是什麼意思? – Kulasangar

+1

您的qquery將在testx表中查找rwo值之間的時間行。如果您沒有在該時間列上定義數據庫索引,那麼MySQL將進行全表掃描以查找要查找的行。如果您定義了索引,則可以使用該索引更快地查找行。 –

回答

0

,你可以在其他的方式做:

創建選擇這個Concats

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

的結果是這樣的:

結果

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> 

,您可以直接在插入語句中對此進行concat,並且只讀取一行,並且只寫入和執行一條語句。

您的代碼

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,並用這些數值對生成第二個準備好的語句 –