某些优化适用于使用IN(或=ANY)来测试子查询结果的比较,特别是关于NULL带来的。讨论的最后一部分建议如何优化。
以下两个表数据基本一致都在一万左右
考虑以下子查询比较:
SELECT
*
FROM
retired_cadre_base
WHERE
cardre_id IN (
SELECT
cardre_id
FROM
retired_cadre_family
WHERE
post_code = '317000')
MySQL“从外到内”执行查询。也就是说,它首先获取外部表达式的值,然后运行子查询并获取它产生的行。
这里的优化可以是赋连接条件于子查询,只有内部表达式inner_expr等于outer_expr的行才是所关注的。这是通过向子查询的WHERE子句下推一个适当的相等项来实现的,限制查询范围。转换后的SQL语句如下所示:
SELECT
*
FROM
retired_cadre_base a
WHERE
EXISTS (
SELECT
1
FROM
retired_cadre_family b
WHERE
post_code = '317000'
AND a.cardre_id = b.cardre_id)
转换之后,MySQL就能够使用下推而来的等式去限制行的数量,即在计算子查询时必须使用该等式进行检查。
更一般地说,将N个值与返回N个行值的子查询进行比较时,也需要进行同样的转换。如果oe_i和ie_i分别代表外部和内部表达式的值,则子查询比较的示例如下:
(oe_1, ..., oe_N) IN
(SELECT ie_1, ..., ie_N FROM ... WHERE subquery_where)
变成:
EXISTS (SELECT 1 FROM ... WHERE subquery_where
AND oe_1 = ie_1
AND ...
AND oe_N = ie_N)
为了简单起见,下面的讨论假释使用的是一对外部表达式和内部表达式的值。
如果以下任何一个条件为真,则上述讨论过的“下推”策略也有效:
outer_expr和inner_expr都不能为NULL。
如果该子查询是WHERE子句中的OR或AND的组成部分,则MySQL假设你不会在意。因此你不必区分子查询结果是NULL还是FALSE。优化器注意到另一种不必区分子查询结果是NULL或FALSE的实例,请看如下构建的条件:
... WHERE outer_expr IN (subquery)
在这种情况下,WHERE子子句都会拒绝不管IN (subquery)返回NULL还是FALSE时的行。
假设已知outer_expr的值是非空的,但是,子查询不能产生符合outer_expr = inner_expr的行。那么,outer_expr IN (SELECT inner_expr …)计算结果如下:
如果SELECT产生的任何行的条件是inner_expr是NULL,那么以上表达式计算结果是NULL
如果SELECT产生的只有非空值或什么也没有产生,那么以上表达式计算结果是FALSE
在这种情况下,寻找符合outer_expr = inner_expr的方法已无效。虽然寻找这样的行是必要的,但是如果找不到,那么也要寻找符合inner_expr is NULL的行。粗略地说,该子查询可以被转换成以下形式:
EXISTS (SELECT 1 FROM .