2014-01-22 81 views
2

語境最快捷的方法來比較兩個字符串數組

我寫了一個小的Java應用程序從甲骨文到微軟的數據遷移的基本測試。

的應用程序做以下的事情:

  • 查詢甲骨文USER_TAB_COLUMNS表來收集有關每個表的細節和它的領域。
  • 根據收集的信息生成SELECT語句
  • 在數據庫的ORACLE和Microsoft版本上運行SELECT語句,並將結果保存爲Table對象中每行的字符串。
  • 對於每個表,比較行以找出差異
  • 爲每個表輸出文本文件,列出不匹配的行。 (對於分析)

問題

我遇到的問題是在這兩個字符串數組我有(甲骨文行和微軟排)的比較。 對於某些表格,可能會有近一百萬行數據。儘管我現在的代碼可以在幾秒鐘內將1000行Oracle數據庫與Microsoft數據庫相匹配,但時間會相加。

在定影問題

  • 電流試圖在數據,而不是比較期間讀取數據時拼接到「行」的字符串。 (之前我有字段作爲有自己的字符串,並在比較之前連接)
  • 一旦找到一行匹配已經打破內循環。
  • 從循環中刪除'oracleTable.getRows()。size()',只執行一次該計算。

理念

  • 刪除行計數器。 (這是否會產生很大的不同?難以在沒有計數器的情況下觀察進度/速度,因此很難說)
  • 從匹配的列表中刪除匹配的Microsoft行。 (我認爲從Microsoft行列表中刪除字符串是一個好主意,這樣相同的行就不會進行兩次比較了,我不確定這是否會增加更多的處理量,因爲它很難去除從同時通過它迭代一個列表。

代碼

 numRowsOracle = oracleTable.getRows().size(); 
     numRowsMicrosoft = msTable.getRows().size(); 

     int orRowCounter = 0; 
     boolean matched; 

     // Each Oracle Row 
     for (String or : oracleTable.getRows()) { 
      matched = false; 
      orRowCounter++; 

      if (orRowCounter % 1000 == 0) { 
       System.out.println("Oracle Row: " + orRowCounter + "/" 
         + numRowsOracle); 
      } 

      // Each Microsoft Row 
      for (String mr : msTable.getRows()) { 
       if (mr.equalsIgnoreCase(or)) { 
        matched = true; 
        break; 
       } 
      } 
      if (!matched) { // Adding row to list of unmatched 
       unmatchedRowStrings.add(or); 
      } 
     } 
     // Writing report on table. 
     exportlogs.writeTableLog(td.getTableName(), unmatchedRowStrings 
       .size(), unmatchedRowStrings, numRowsOracle, 
       numRowsMicrosoft); 
    } 

就如何加快這有什麼建議?我會接受的想法,不僅加快了比較兩個數組,而且存儲數據不同,我沒有使用其他類型的字符串存儲,比如hashmaps。不同的東西會更快嗎?

回答

2

這是未經測試的,所以請帶上一點鹽,特別是如果您使用非ASCII字符。

您可以在一次傳遞中對數據進行小寫(或大寫)驗證,然後使用哈希集來驗證它們。

// make a single pass over oracle rows, so O(n) 
Set<String> oracleLower = new HashSet<>(); 
for(String or : oracleTable.getRows()) { 
    oracleLower.add(or.toLowerCase()); 
} 

// make a single pass over msft rows, so O(n) 
Set<String> msftLower = new HashSet<>(); 
for(String ms : microsoftTable.getRows()) { 
    msftLower.add(ms.toLowerCase()); 
} 

// make a single pass over oracle rows, again O(n) 
for(String or : oracleLower) { 
    // backed by a hash table, this has a constant time lookup 
    if(!msftLower.contains(or)) { 
     unmatched.add(or); 
    } 
} 

每個操作都是O(n),這要歸功於哈希表。不過,這需要雙倍的空間需求。優化可能是必要的,只有一個集合小寫(可能是MSFT),並且只讓另一個(可能是ORACLE)在循環內小寫 - 然後它會更像for(String or : oracleTable.getRows()) { or = or.toLowerCase(); if(!msftLower.contains(or)) { ... } }

+1

由於你的代碼是寫的,你不會真的需要'oracleLower'。你可以直接使用'oracleTable'(如果需要,可以直接轉換爲小寫)。 – Dukeling

+0

@Dukeling這是絕對正確的。我開始詳細說明這一點。我只是試圖說明從概念上說,我們只使用數據的小寫形式。此外,如果我們發現它們有用,則使用單獨的集合可以利用內置機制,如'retainAll'或'removeAll'。 – corsiKa

+0

看起來太簡單不行。我會放棄它。謝謝。 –