SQL比较/同步速度

时间:2014-01-14 15:46:18

标签: c# sql

我有两个数据表,我们只需称它们为db1db2db2包含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 - &gt; 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
        }

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

如果你有一个可以订购和比较的唯一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