2014-01-22 78 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

看起来太简单不行。我会放弃它。谢谢。 –