我发现此样本面试问答集已复制在此处。但是我不太了解代码。UNION ALL怎样才能变成这样的UNIION(不同)?另外,为什么此代码更快?
问题
使用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 (a.k.a., UNION DISTINCT) command, while avoiding much of its performance hit.
但是在示例中,第一个查询的条件为column a,而第二个查询的条件为column b。这可能来自难以优化的查询:
a
b
SELECT * FROM mytable WHERE a=X OR b=Y
使用简单的B树索引很难优化此查询。引擎是否在列上搜索索引a?还是列上b?无论哪种方式,搜索其他术语都需要进行表格扫描。
因此,使用UNION可以将两个查询分开为一个查询的技巧。每个子查询可以为每个搜索词使用最佳索引。然后使用UNION合并结果。
但是,这两个子集可能会重叠,因为某些行b=Y也可能同时存在,a=X在这种情况下,这两个行都出现在两个子集中。因此,您必须进行重复消除,否则在最终结果中将看到一些行两次。
b=Y
a=X
SELECT * FROM mytable WHERE a=X UNION DISTINCT SELECT * FROM mytable WHERE b=Y
UNION DISTINCT之所以昂贵,是因为典型的实现对行进行排序以查找重复项。就像您使用一样SELECT DISTINCT ...。
UNION DISTINCT
SELECT DISTINCT ...
我们还认为,如果您要合并的行的两个子集在两个子集中都有很多行,那么它的工作就更加“浪费”了。有很多行要消除。
但是,如果可以保证两组行已经不同,则无需消除重复项。也就是说,如果您保证没有重叠。如果您可以依靠它,那么消除重复将永远是绝妙的选择,因此查询可以跳过该步骤,从而跳过代价高昂的排序。
如果您更改查询以确保它们选择行的不重叠子集,那将是双赢。
保证这两个集合没有重叠。如果第一个集合的行在哪里a=X,第二个集合的行在哪里a!=X,则两个集合中都不能有行。
a!=X
因此,第二个查询仅捕获where中的 某些 行b=Y,但捕获a=X AND b=Y第一组中已经包含的任何行。
a=X AND b=Y
因此,该查询实现了对两个OR词的优化搜索,而不会产生重复项,并且不需要任何UNION DISTINCT操作。
OR