10.2.1.5 引擎条件下推优化
这个优化提高了直接比较非索引列和常量的效率。在这种情况下,条件被“下推”到存储引擎中评估。这优化只能由NDB
存储引擎使用。
对于 NDB 集群,这个优化可以消除在数据节点和 MySQL 服务器之间传输不匹配行的需要,并且可以加速查询,提高速度5到10倍于不使用条件下推的情况。
假设一个 NDB 集群表定义如下:
CREATE TABLE t1 (
a INT,
b INT,
KEY(a)
) ENGINE=NDB;
可以使用引擎条件下推优化的查询,如下所示,其中包括非索引列和常量的比较:
SELECT a, b FROM t1 WHERE b = 10;
可以在EXPLAIN
输出中看到引擎条件下推优化的使用:
mysql> EXPLAIN SELECT a, b FROM t1 WHERE b = 10\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 10
Extra: Using where with pushed condition
然而,引擎条件下推不能用于以下查询:
SELECT a,b FROM t1 WHERE a = 10;
因为存在于列a上的索引(索引访问方法更高效,因此将被选择而不是条件下推)。
引擎条件下推也可以在使用>或<操作符比较带有索引列和常量时使用:
mysql> EXPLAIN SELECT a, b FROM t1 WHERE a < 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: range
possible_keys: a
key: a
key_len: 5
ref: NULL
rows: 2
Extra: Using where with pushed condition
引擎条件下推还支持以下比较:
-
column
[NOT] LIKEpattern
pattern
必须是一个字符串字面量,用于匹配的模式;语法请见第14.8.1节,“字符串比较函数和操作符”。 -
column
IS [NOT] NULL -
column
IN (value_list
)每个
value_list
中的项目都必须是一个常量字面值。 -
column
BETWEENconstant1
ANDconstant2
constant1
和constant2
都必须是一个常量字面值。
在前面的列表中,所有情况都可以将条件转换为一个或多个直接比较列和常量之间的比较。
引擎条件推送是默认启用的。要在服务器启动时禁用它,请将optimizer_switch
系统变量的engine_condition_pushdown
标志设置为 off
。例如,在一个my.cnf
文件中,使用这些行:
[mysqld]
optimizer_switch=engine_condition_pushdown=off
在运行时禁用条件推送,如下所示:
SET optimizer_switch='engine_condition_pushdown=off';
限制。 引擎条件下推是受以下限制的:
之前,引擎条件下推只能引用同一个表中的列值。在 NDB 8.4 中,可以从查询计划中的前面表中引用列值。这减少了 SQL 节点在连接处理期间需要处理的行数。可以并行在 LDM 线程中执行过滤,而不是在单个 mysqld 进程中。这可能会提高查询的性能。
NDB
可以使用扫描推送外连接,如果在同一个连接nest中没有任何不可下推条件,或者它依赖的连接nest中的任何表上没有不可下推条件。这也适用于半连接,假设使用的是 firstMatch
优化策略(见Optimizing IN and EXISTS Subquery Predicates with Semijoin Transformations)。
连接算法不能与之前表中的引用列结合在一起的情况:
-
当任何被引用的前面表位于连接缓冲区中。在这种情况下,每个从扫描过滤表中检索的行都将与缓冲区中的每一行进行匹配。这意味着,在生成扫描过滤时,不能从单个特定的行中获取列值。
-
当列来自推送连接的子操作。在这种情况下,来自祖先操作的行还没有被检索出来,当扫描过滤被生成时。
祖先表中的列可以被推下,假设它们满足之前列出的要求。使用之前创建的表t1
的一个示例查询如下:
mysql> EXPLAIN
-> SELECT * FROM t1 AS x
-> LEFT JOIN t1 AS y
-> ON x.a=0 AND y.b>=3\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: x
partitions: p0,p1
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: y
partitions: p0,p1
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
filtered: 100.00
Extra: Using where; Using pushed condition (`test`.`y`.`b` >= 3); Using join buffer (hash join)
2 rows in set, 2 warnings (0.00 sec)