SQL对比两张90万条记录表差异耗时久,如何提升检测效率?
首先,你的NOT IN查询慢的核心原因通常有两个:一是**ColumnOfInterest字段没有索引**,导致两张表都要做全表扫描;二是NOT IN对NULL值的处理很敏感(如果TableA的ColumnOfInterest存在NULL,整个查询会返回空结果),而且数据库对NOT IN的执行计划优化往往不如JOIN或EXISTS。
下面是几个经过实践验证的高效方案,按优先级排序:
1. 先给关键字段加索引(基础中的基础)
不管用哪种查询,先确保两张表的ColumnOfInterest都有索引,这能把全表扫描变成索引查找,速度提升几个数量级:
-- 给TableA加索引 CREATE INDEX idx_tableA_column ON TableA(ColumnOfInterest); -- 给tableB加索引 CREATE INDEX idx_tableB_column ON tableB(ColumnOfInterest);
如果字段是唯一的,用UNIQUE INDEX效果更好,数据库会做更优的优化。
2. 用LEFT JOIN + IS NULL替代NOT IN
这是最通用的高效写法,几乎所有数据库都支持,而且不会受NULL值影响:
SELECT tableB.ColumnOfInterest, tableB.City, tableB.Province FROM tableB LEFT JOIN TableA ON tableB.ColumnOfInterest = TableA.ColumnOfInterest WHERE TableA.ColumnOfInterest IS NULL;
原理:LEFT JOIN会保留tableB的所有记录,然后匹配TableA中相同的ColumnOfInterest;WHERE IS NULL筛选出那些在TableA中找不到匹配的记录,也就是你要的缺失项。
3. 用NOT EXISTS替代NOT IN
NOT EXISTS是半连接查询,数据库会在找到第一条匹配记录后就停止扫描,比NOT IN更高效,尤其是当TableA有索引时:
SELECT tableB.ColumnOfInterest, tableB.City, tableB.Province FROM tableB WHERE NOT EXISTS ( SELECT 1 -- 这里用1比选字段更轻量,只检查存在性 FROM TableA WHERE TableA.ColumnOfInterest = tableB.ColumnOfInterest );
注意:子查询里用SELECT 1就够了,不需要返回实际字段,减少不必要的资源消耗。
4. 用EXCEPT(部分数据库支持)
如果你的数据库支持EXCEPT(比如PostgreSQL、MySQL 8.0+、SQL Server),可以直接用集合运算,写法更简洁:
-- 对比整行记录(如果需要确认City、Province也一致的话) SELECT ColumnOfInterest, City, Province FROM tableB EXCEPT SELECT ColumnOfInterest, City, Province FROM TableA; -- 只对比ColumnOfInterest,再关联回tableB拿其他字段 SELECT b.ColumnOfInterest, b.City, b.Province FROM ( SELECT ColumnOfInterest FROM tableB EXCEPT SELECT ColumnOfInterest FROM TableA ) AS missing JOIN tableB b ON missing.ColumnOfInterest = b.ColumnOfInterest;
额外小技巧:快速判断是否存在缺失(不需要具体记录)
如果你只是想确认有没有缺失,不需要知道具体哪些记录,可以用统计计数对比,速度极快:
-- 统计tableB中唯一的ColumnOfInterest数量 SELECT COUNT(DISTINCT ColumnOfInterest) FROM tableB; -- 统计TableA中唯一的ColumnOfInterest数量 SELECT COUNT(DISTINCT ColumnOfInterest) FROM TableA;
如果两个数量不一致,说明肯定有缺失;如果一致,再用上面的方法找具体记录。
内容的提问来源于stack exchange,提问作者PHPDev

