有效地获得大数据集的差异?

时间:2015-08-07 21:12:54

标签: php mysql diff large-data

我需要能够区分两个查询的结果,显示“旧”集中但不在“新”中的行...然后显示“新”中的行“但不是旧的。”

现在,我将结果拉入数组,然后执行array_diff()。但是,我正在遇到一些资源和时间问题,因为这些集合各自接近100万行。

两个结果集中的模式相同(除了setId数和表的自动增量数),所以我假设有一个很好的方法直接在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之间的添加/删除。

因此,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的解决方案对我来说很好。

2 个答案:

答案 0 :(得分:0)

您可以使用existsnot 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

答案 1 :(得分:0)

我们最终做的是将校验和列添加到所需的表格中。这样,不必选择多列进行比较,可以针对单个列(校验和值)完成差异。

校验和值是序列化数组的简单md5散列,其中包含要扩散的列。所以...在PHP中就是这样:

$checksumString = serialize($arrayOfColumnValues);
$checksumValue = md5($checksumString);

然后将$ checksumValue插入/更新到表中,然后我们可以更容易地在单个列上执行连接/联合等以查找差异。它最终看起来像这样:

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);

这足以达到我的目的,至少目前为止: - )