高效获取大数据集的差异?
Efficiently get diff of large data set?
我需要能够区分两个查询的结果,显示 "old" 集中但不在 "new"... 中的行,然后显示这些行在 "new" 集合中但不在旧集合中。
现在,我将结果拉入一个数组,然后执行 array_diff()。但是,我遇到了一些资源和时间问题,因为每个集合接近 100 万行。
两个结果集中的架构相同(除了 setId 编号和 table 的自动递增编号),所以我认为有一个很好的方法可以直接在 MySQL 中执行此操作。 .. 但我没有找到方法。
Example Table Schema:
rowId,setId,userId,name
Example Data:
1,1,user1,John
2,1,user2,Sally
3,1,user3,Tom
4,2,user1,John
5,2,user2,Thomas
6,2,user4,Frank
我需要做的是找出 setId 1 和 setId 2 之间的 adds/deletes。
所以,diff 的结果应该(例如)显示:
Rows that are in both setId1 and setId2
1,1,user1,John
Rows that are in setId 1 but not in setId2
2,1,user2,Sally
3,1,user3,Tom
Rows that are in setId 2 but not in setId1
5,2,user2,Thomas
6,2,user4,Frank
我想这就是所有的细节。我想我的例子是正确的。任何帮助,将不胜感激。 MySQL 或 PHP 中的解决方案对我来说很好。
您可以使用 exists
或 not exists
来获取在这两个集合中或仅在一组中的行。
第 1 组但不第 2 组的用户(只需翻转相反的表格):
select * from set1 s1
where set_id = 1
and not exists (
select count(*) from set1 s2
where s1.user1 = s2.user1
)
两个集合中的用户
select * from set2 s2
where set_id = 2
and exists (
select 1 from set1 s1
where s1.setId = 1
and s2.user1 = s1.user1
)
如果您只想在两个组中使用不同的用户,那么 group by user1
:
select min(rowId), user1 from set1
where set_id in (1,2)
group by user1
having count(distinct set_id) = 2
或组中的用户而不是其他用户
select min(rowId), user1 from set1
where set_id in (1,2)
group by user1
having count(case when set_id <> 1 then 1 end) = 0
我们最终做的是向需要区分的必要表添加校验和列。这样,不必 select 多列进行比较,差异可以针对单个列(校验和值)进行。
校验和值是一个序列化数组的简单 md5 散列,其中包含要进行比较的列。所以...在PHP中是这样的:
$checksumString = serialize($arrayOfColumnValues);
$checksumValue = md5($checksumString);
然后 $checksumValue 将 inserted/updated 放入表中,然后我们可以更轻松地在单个列上执行 joins/unions 等以查找差异。它最终看起来像这样:
SELECT i.id, i.checksumvalue
FROM SAMPLE_TABLE_I i
WHERE i.checksumvalue not in(select checksumvalue from SAMPLE_TABLE_II)
UNION ALL
SELECT ii.id, ii.checksumvalue
FROM SAMPLE_TABLE_II ii
WHERE ii.checksumvalue not in(select checksumvalue from SAMPLE_TABLE_I);
这对我来说运行得足够快了,至少现在是这样:-)
我需要能够区分两个查询的结果,显示 "old" 集中但不在 "new"... 中的行,然后显示这些行在 "new" 集合中但不在旧集合中。
现在,我将结果拉入一个数组,然后执行 array_diff()。但是,我遇到了一些资源和时间问题,因为每个集合接近 100 万行。
两个结果集中的架构相同(除了 setId 编号和 table 的自动递增编号),所以我认为有一个很好的方法可以直接在 MySQL 中执行此操作。 .. 但我没有找到方法。
Example Table Schema:
rowId,setId,userId,name
Example Data:
1,1,user1,John
2,1,user2,Sally
3,1,user3,Tom
4,2,user1,John
5,2,user2,Thomas
6,2,user4,Frank
我需要做的是找出 setId 1 和 setId 2 之间的 adds/deletes。
所以,diff 的结果应该(例如)显示:
Rows that are in both setId1 and setId2
1,1,user1,John
Rows that are in setId 1 but not in setId2
2,1,user2,Sally
3,1,user3,Tom
Rows that are in setId 2 but not in setId1
5,2,user2,Thomas
6,2,user4,Frank
我想这就是所有的细节。我想我的例子是正确的。任何帮助,将不胜感激。 MySQL 或 PHP 中的解决方案对我来说很好。
您可以使用 exists
或 not exists
来获取在这两个集合中或仅在一组中的行。
第 1 组但不第 2 组的用户(只需翻转相反的表格):
select * from set1 s1
where set_id = 1
and not exists (
select count(*) from set1 s2
where s1.user1 = s2.user1
)
两个集合中的用户
select * from set2 s2
where set_id = 2
and exists (
select 1 from set1 s1
where s1.setId = 1
and s2.user1 = s1.user1
)
如果您只想在两个组中使用不同的用户,那么 group by user1
:
select min(rowId), user1 from set1
where set_id in (1,2)
group by user1
having count(distinct set_id) = 2
或组中的用户而不是其他用户
select min(rowId), user1 from set1
where set_id in (1,2)
group by user1
having count(case when set_id <> 1 then 1 end) = 0
我们最终做的是向需要区分的必要表添加校验和列。这样,不必 select 多列进行比较,差异可以针对单个列(校验和值)进行。
校验和值是一个序列化数组的简单 md5 散列,其中包含要进行比较的列。所以...在PHP中是这样的:
$checksumString = serialize($arrayOfColumnValues);
$checksumValue = md5($checksumString);
然后 $checksumValue 将 inserted/updated 放入表中,然后我们可以更轻松地在单个列上执行 joins/unions 等以查找差异。它最终看起来像这样:
SELECT i.id, i.checksumvalue
FROM SAMPLE_TABLE_I i
WHERE i.checksumvalue not in(select checksumvalue from SAMPLE_TABLE_II)
UNION ALL
SELECT ii.id, ii.checksumvalue
FROM SAMPLE_TABLE_II ii
WHERE ii.checksumvalue not in(select checksumvalue from SAMPLE_TABLE_I);
这对我来说运行得足够快了,至少现在是这样:-)