我发现在 toptal 上发布的这个样本面试问题和答案被复制在这里。但是我真的不明白代码。一个 UNION ALL 怎么能变成一个 UNION (distinct) 呢?另外,为什么这段代码更快?
问题
使用 UNION ALL(不是 UNION)编写 SQL 查询,使用 WHERE 子句消除重复项。你为什么要这样做? 隐藏答案 您可以使用 UNION ALL 避免重复,并且仍然比 UNION DISTINCT(实际上与 UNION 相同)通过运行这样的查询运行得更快:
回答
SELECT * FROM mytable WHERE a=X UNION ALL SELECT * FROM mytable WHERE b=Y AND a!=X
关键是 AND a!=X 部分。这为您提供了 UNION(又名 UNION DISTINCT)命令的好处,同时避免了它的大部分性能损失。
最佳答案
但在示例中,第一个查询的条件是a
列,而第二个查询的条件是b
列。这可能来自难以优化的查询:
SELECT * FROM mytable WHERE a=X OR b=Y
这个查询很难用简单的 B 树索引优化。引擎是否在 a
列上搜索索引?或者在 b
列?无论哪种方式,搜索其他术语都需要表格扫描。
因此,使用 UNION 将一个术语分成两个查询的技巧。每个子查询可以为每个搜索词使用最佳索引。然后使用 UNION 组合结果。
但是这两个子集可能会重叠,因为某些 b=Y
的行也可能有 a=X
,在这种情况下,这样的行会出现在两个子集中。因此,您必须进行重复消除,否则在最终结果中会看到某些行两次。
SELECT * FROM mytable WHERE a=X
UNION DISTINCT
SELECT * FROM mytable WHERE b=Y
UNION DISTINCT
很昂贵,因为典型的实现对行进行排序以查找重复项。就像您使用 SELECT DISTINCT ...
一样。
我们还认为,如果要合并的两个行子集在两个子集中都出现了很多行,则工作会更加“浪费”。需要删除很多行。
但如果您可以保证两组行已经不同,则无需消除重复项。也就是说,如果你保证没有重叠。如果您可以依赖它,那么消除重复项始终是空操作,因此查询可以跳过该步骤,从而跳过代价高昂的排序。
如果您更改查询以保证它们选择不重叠的行子集,那就成功了。
SELECT * FROM mytable WHERE a=X
UNION ALL
SELECT * FROM mytable WHERE b=Y AND a!=X
这两个集合保证没有重叠。如果第一组包含 a=X
的行,第二组包含 a!=X
的行,则两组中都没有行。
因此,第二个查询只捕获 一些 b=Y
的行,但是 a=X AND b=Y
的任何行已包含在第一组中。
因此查询实现了对两个OR
项的优化搜索,不会产生重复项,也不需要UNION DISTINCT
操作。
关于mysql - SQL UNION ALL 消除重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41729082/