8月 24, 2014 |
Nix.Huang
考虑下面的子查询:
outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)
MySQL从外到内的处理查询语句,先获得外层表达式outer_expr的值,然后执行子查询最后获取它产生的行。
一个非常有用的优化师通知子查询,inner_expr= outer_expr的行才是我们关心的行,可以通过将一个合适的相等条件加入子查询的where从句,这个查询语句被转换为:
EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)
转换之后,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)
为了简单,接下来的讨论假设外层和内层都是单个值,前面讨论的转换是有限制条件的,只有当我们忽略NULL值才行,推入策略只有当满足下面的两个条件后才能生效:
outer_expr 和 inner_expr都不能为NULL
你也不需要区分子查询的NULL和FALSE,(如果子查询是WHERE从句的OR 或AND表达式的一部分,MySQL假设你不在意)。
当上述条件的一个或者都不满足时,优化变得复杂,假设outer_expr是一个非NULL值,但是子查询没有产生满足outer_expr = inner_expr的行,outer_expr IN (SELECT ...)就按照下面的规则求值:
· NULL, 如果SELECT产生inner_expr = NULL任意行
· FALSE, 如果SELECT仅产生非NULL或者没有任何输出。
这种情况, 使用outer_expr = inner_expr来查找行的方式不再有效,查找这样的行还是有必要的,但是如果没有找到,就要查找inner_expr is NULL的行,大致的讲,子查询能别转换成:
EXISTS (SELECT 1 FROM ... WHERE subquer