mysql - SQL UNION ALL 消除重复项

标签 mysql sql sql-server union union-all

我发现在 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/

相关文章:

sql-server - 令人困惑的 IDENTITY_INSERT 错误,表示它已经在另一个表中

MySQL 动态键/对转换为单个记录集

php - MySQL根据表名和多表数据格式化结果

MySQL列操作废话

sql - 分解 SQL 代码 - MS SQL Server

java - Hibernate,在一个事务中修改多个表的正确方法

mysql - 教义得到结果问题

python - Django:如何获取原始 SQL "COUNT(*)"查询的结果?

mysql - 如何复制 SQL 数据库表中的所有行并更改其中一列中的数据?

sql - ORA-00942:表或 View 不存在(当使用单独的sql时有效,但在oracle函数中不起作用)