繁体   English   中英

SQL UNION ALL 消除重复

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM