比较两个字符串数组的最快方法

时间:2014-01-22 11:28:08

标签: java arrays performance

上下文

我编写了一个小型Java应用程序,用于从Oracle到Microsoft的数据迁移的基本测试。

该应用程序执行以下操作:

  • 查询Oracle USER_TAB_COLUMNS表以收集有关每个表及其字段的详细信息。
  • 根据收集的信息生成SELECT语句
  • 在ORACLE和Microsoft版本的数据库上运行SELECT语句,将结果保存为Table对象中每一行的String。
  • 对于每个表,比较行以查找差异
  • 输出每个表的文本文件,列出不匹配的行。 (用于分析)

问题

我遇到的问题是比较我拥有的两个String数组(Oracle Rows和Microsoft Rows)。 对于某些表,可能有近一百万行数据。虽然我的当前代码可以在几秒钟内将1000个Oracle行与Microsoft的行匹配 - 但时间会增加。

当前尝试修复问题

  • 在读取数据时而不是在比较期间连接到'row'字符串。 (之前我有字段,因为有自己的字符串,并在比较之前连接)
  • 找到一行匹配后,从内循环中断。
  • 从循环中删除'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);
    }

有关如何加快速度的任何建议?我接受的想法不仅是加快比较两个数组,而且还以不同的方式存储数据。我没有使用其他类型的String存储,例如hashmaps。不同的东西会更快吗?

1 个答案:

答案 0 :(得分: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)) { ... } }