我有两个数据表,我们只需称它们为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.
}
}
此版本在一段时间后变得非常慢。我在谈论成千上万的记录。
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
}
哪种方式更快(更好)?我还有其他选择吗?
答案 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