但在这个例子中,第一个查询对列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 ...
一样。
我们还有一个感觉,如果你要union的两个子集中有很多行同时出现在这两个子集中,那么这将会更加“浪费“。因为需要消除大量的重复行。
但是,如果你能够保证这两组行已经不同,即不存在重叠部分,那么就没有必要消除重复项了。如果你能够依靠这一点,那么查询总是可以跳过消除重复项的步骤,也因此可以跳过昂贵的排序操作。
如果你修改查询以确保选择不重叠的行子集,那么就可以提高效率。
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
,但过滤掉了第一个查询的结果。它只是使用WHERE
子句进行过滤,而不是使用昂贵的DISTINCT
操作。 - Siyuala
的主键,则由于select *
,不会出现重复项。 - Dan Bracuk