[英]SQL UNION ALL to eliminate duplicates
我发现在 toptal 上发布的这个样本面试问题和答案转载在这里。 但我真的不明白代码。 UNION ALL 怎么能变成这样的UNIION(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
The key is the AND a!=X part. This gives you the benefits of the UNION (aka, UNION DISTINCT) command, while avoiding much of its performance hit.
但在实施例中,第一查询具有上塔的条件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
操作。
如果表具有唯一标识符 - 主键,则问题将是正确的。 否则每个选择都可以返回许多相同的行。
要了解为什么它可以更快,让我们看看数据库如何执行 UNION ALL 和 UNION。
第一个是来自两个独立查询的简单连接结果。 这些查询可以并行处理并一一传递给客户端。
二是加入+区分。 要从 2 个查询中区分记录,db 需要将所有记录都保存在内存中,或者如果内存不够,db 需要将它们存储到临时表中,然后选择唯一的。 这就是性能下降的地方。 DB 非常聪明,区分算法开发得很好,但对于大型结果集,无论如何这可能是一个问题。
如果在过滤时使用索引,UNION ALL + 额外的 WHERE 条件可以更快。 所以,这里的表演魔术。
我想它会起作用
select col1 From (
select row_number() over (partition by col1 order by col1) as b, col1
from (
select col1 From u1
union all
select col1 From u2 ) a
) x
where x.b =1
这也将执行相同的技巧:
select * from (
select * from table1
union all
select * from table2
) a group by
columns
having count(*) >= 1
或者
select * from table1
union all
select * from table2 b
where not exists (select 1 from table1 a where a.col1 = b.col1)
最简单的方法是这样的,尤其是当你有很多列时:
SELECT *
INTO table2
FROM table1
UNION
SELECT *
FROM table1
ORDER BY column1
我来宾这是对的(甲骨文):
select distinct * from (
select * from test_a
union all
select * from test_b
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.