我发现这个样本面试的问题和答案在这里转载。但我真的不懂代码。 UNION ALL如何变成UNIION(不同)?另外,为什么这段代码更快?
问题
使用UNION ALL(非UNION)编写SQL查询,该查询使用WHERE子句来消除重复项。你为什么要这样做? 隐藏答案 使用UNION ALL可以避免重复,并且通过运行如下查询仍然比UNION DISTINCT(实际上与UNION相同)运行得快得多:
ANSWER
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 (a.k.a., UNION DISTINCT) command, while avoiding much of its performance hit.
答案 0 :(得分:8)
但是在示例中,第一个查询在列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
操作。
答案 1 :(得分:0)
如果表具有唯一标识符 - 主键,则问题将是正确的。否则每个选择都可以返回许多相同的行。
要理解为什么它可以更快地让我们看看数据库如何执行UNION ALL和UNION。
第一个是两个独立查询的简单连接结果。这些查询可以并行处理并逐个传递给客户端。
第二个是加入+区别。对于来自2个查询的不同记录,db需要将它们全部存储在内存中,或者如果内存不足,db需要将它们存储到临时表中,然后选择唯一的。这是性能下降的地方。 DB非常聪明,并且区分算法开发得很好,但对于大型结果集,无论如何都可能是一个问题。
如果在过滤时使用索引,UNION ALL +附加WHERE条件会更快。 所以,这里是表演魔术。
答案 2 :(得分:0)
我想它会起作用
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
答案 3 :(得分:0)
这也会起到相同的作用:
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)
答案 4 :(得分:0)
最简单的方法是这样的,特别是如果你有很多列:
SELECT *
INTO table2
FROM table1
UNION
SELECT *
FROM table1
ORDER BY column1
答案 5 :(得分:0)
我认为这是对的(甲骨文):
select distinct * from (
select * from test_a
union all
select * from test_b
);