【问题标题】:SQL comparsion/synchronization speedSQL比较/同步速度
【发布时间】:2014-01-14 15:46:18
【问题描述】:

我有两个数据表,我们就叫它们db1 和db2。 db2 包含 db1 的所有记录,但 db1 不包含 db2 的所有记录(它们都有相同的列)。我必须每天在db1 中检查修改,并为db2 应用相同的修改。

  • 目前我的工具将两个表“导出”到DataTables,执行转换并将记录更新/导入到db2:

SELECT * FROM db1 -> db1_table

SELECT * FROM db2 -> db2_table

for (int i = 0; i < db1_table.Rows.Count; i++)
    {
        for (int j = 0; j < db2_table.Rows.Count; j++)
            {
                //if db1_table.Rows[i] != db2_table.Rows[j] -> UPDATE db2 SET etc.
                //if db1_table.Rows[i] doesn't exist in db2 -> INSERT INTO db2 etc.
            }
    }

这个版本一段时间后变得很慢。我说的是成千上万条记录。

  • 另一个是我最初的想法,但我发现它很慢。我拉出整个 db1,遍历它的所有记录,每次都执行一个 sql 查询:

SELECT * FROM db1 -> db1_table

for (int i = 0; i < db1_table.Rows.Count; i++)
        {
            //SELECT * FROM db2 WHERE "attributes LIKE db1_table.Rows[i]
            //do the comparsion here and execute the UPDATE/INSERT commands if necessary
        }

哪种方式更快(更好)?我还有其他选择吗?

【问题讨论】:

  • 这很复杂。 db1 不是我的,我只有读取权限,并且所有者不希望我的用户通过我的应用程序加载他的数据库,因此我必须使用自己的。
  • 如果是SQL server 检查this SO QnA
  • 这些数据表在不同的数据库中,在不同的位置,所以我相信我每次要同步时都无法导出整个表。

标签: c# sql


【解决方案1】:

旁注:你真的不应该首先将重复数据存储在具有相同结构的两个表中......

旁注:您应该在 SQL 中进行此更新。

回答您的实际问题。您遇到的是 O(N^2) 算法复杂度。如果您为其中一个表构建哈希表(字典),并且只在另一个表上进行迭代,则它可以减少到 O(N) 左右。当您查找匹配项时,您会查看哈希表而不是迭代,这大约是 O(1) 而不是 O(N)。您只需要一个用于散列的良好键值。

类似这样的:

var dict = db2_table.Rows.Cast<DataRow>().ToDictionary(row2 => row2["keycolumn"].Value); // this is the hashing, make sure no duplicate keys exist!
foreach (DataRow row1 in db1_table.Rows) {
    DataRow row2;
    if (dict.TryGetValue(row1["keycolumn"].Value, out row2)) {
        // row1 and row2 match by the key column, do something with them
        dict.Remove(row2["keycolumn"].Value);
    }
    // else no match, row1 must be a new row
}
// now dict contains the keys from db2 which have no match in db1, they must have been deleted

【讨论】:

  • 我有一个很好的键值,但是那个哈希表应该看起来像什么?
  • Dictionary&lt;typeofkey, DataRow&gt;。编写一次迭代,将所有 db1 放入字典,然后迭代 db2。
  • 为什么这会比原来的更快?我使用 db1_table 就像使用哈希表一样。
  • 不,您正在迭代 db1 行,这需要 N 步(N=行数),并且每次添加新行时,它都会变慢。在哈希表中,您只需一步即可获得匹配项。这是一个巨大的加速。
  • TryGetValue 如果密钥不存在,则返回 false。
【解决方案2】:

如果您有一个可以订购和比较的唯一 ID,还有另一个选项是 O(n):按 ID 订购两个表并同时遍历它们,生成待处理更改的列表。之后,您可以应用待处理的更改。生成更改列表的原因是,您可以在更改检测结束时将命令一起批处理,并从批量插入、CTE 或临时表等内容中受益以加入删除,以及批处理命令组以进行更新——所有这减少了此类操作中最大的延迟来源之一:数据库往返。

主循环如下所示:

// Assuming that IDs are long.  Change as required.
long db1_id;
long db2_id;
var idsToAppend = new List<long>();
var idsToUpdate = new List<long>();
var idsToDelete = new List<long>();
int i = 0;
int j = 0;
while (i < db1_table.Rows.Count && j < db2_table.Rows.Count) {
    db1_id = db1_table.Rows[i]["ID"];
    db2_id = db2_table.Rows[j]["ID"];
    if (i == db1_table.Rows.Count && j < db2_table.Rows.Count) {
        // There's extra rows in the destination that have been removed from the source
        idsToDelete.Add(db1_id);
        j++;
    } else if (j < db1_table.Rows.Count && j == db2_table.Rows.Count) {
        // There's extra rows in the source that need added to the destination
        idsToAppend.Add(db1_id);
        i++;
    } else if (db1_id == db2_id) {
        // On the same ID in both datasets
        if !(db1_table.Rows[i] == db2_table.Rows[j]) {
            // I know == won't work -- only do this if db1 may change and the changes must be propagated to db2
            idsToUpdate.Add(db1_id);
        }
        i++;
        j++;
    } else if (db1_id > db2_id) {
        // row in db1 was removed, remove row in db2
        idsToDelete.Add(db1_id);
        j++;
    } else {
        // implicit: db1_id < db2_id
        // implicit: row in db1 doesn't exist in db2, needs added
        idsToAppend(db1_id);
        i++;
    }
}
// Walk idsToAppend, idsToUpdate, and idsToDelete applying changes

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 2011-02-20
    • 2019-04-18
    • 2020-08-06
    • 2010-11-30
    • 2015-08-10
    • 1970-01-01
    相关资源
    最近更新 更多