此优化提高了非索引列与常量之间直接比较的效率。在这种情况下,条件会被“下推”到存储引擎以供评估。此优化只能由NDB
存储引擎使用。
对于 NDB 集群,此优化可以消除将不匹配的行在集群的数据节点和发出查询的 MySQL 服务器之间通过网络发送的必要性,并且可以在使用条件下推的情况下将查询速度提高 5 到 10 倍,而条件下推可以但没有使用。
假设 NDB 集群表定义如下
Press CTRL+C to copyCREATE TABLE t1 ( a INT, b INT, KEY(a) ) ENGINE=NDB;
引擎条件下推可以与以下所示的查询一起使用,该查询包括非索引列与常量之间的比较
Press CTRL+C to copySELECT a, b FROM t1 WHERE b = 10;
在EXPLAIN
的输出中可以看到引擎条件下推的使用
Press CTRL+C to copymysql> 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
但是,引擎条件下推不能与以下查询一起使用
Press CTRL+C to copySELECT a,b FROM t1 WHERE a = 10;
引擎条件下推不适用于此处,因为列 a
上存在索引。(索引访问方法将更有效,因此将优先选择它而不是条件下推。)
当使用 >
或 <
运算符将索引列与常量进行比较时,也可能使用引擎条件下推
Press CTRL+C to copymysql> 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] NULLcolumn
IN (value_list
)value_list
中的每个项目都必须是常量字面量值。column
BETWEENconstant1
ANDconstant2
constant1
和constant2
必须分别是常量字面量值。
在前面列表中的所有情况下,都可以将条件转换为列与常量之间的一个或多个直接比较的形式。
引擎条件下推默认情况下处于启用状态。要在服务器启动时禁用它,请将optimizer_switch
系统变量的engine_condition_pushdown
标志设置为 off
。例如,在 my.cnf
文件中,使用以下行
Press CTRL+C to copy[mysqld] optimizer_switch=engine_condition_pushdown=off
在运行时,按如下方式禁用条件下推
Press CTRL+C to copySET optimizer_switch='engine_condition_pushdown=off';
限制。 引擎条件下推受以下限制
以前,引擎条件下推仅限于引用与条件要推送到的同一表的列值的项。在 NDB 9.0 中,还可以从推送的条件中引用查询计划中较早表的列值。这减少了连接处理期间 SQL 节点必须处理的行数。过滤也可以在 LDM 线程中并行执行,而不是在单个 mysqld 进程中执行。这有可能显着提高查询性能。
NDB
可以使用扫描推送外部连接,前提是用于同一连接嵌套的任何表的任何不可推送条件,或其依赖的任何连接嵌套中上方的任何表的任何不可推送条件。对于半连接也是如此,前提是采用的优化策略是 firstMatch
(参见 使用半连接转换优化 IN 和 EXISTS 子查询谓词)。
在以下两种情况下,连接算法不能与来自先前表的引用列组合使用
当任何引用的先前表位于连接缓冲区中时。在这种情况下,从扫描过滤表中检索的每一行都与缓冲区中的每一行匹配。这意味着在生成扫描过滤器时,没有来自特定行的特定列值可以被获取。
当列源自推送连接中的子操作时。这是因为当生成扫描过滤器时,尚未从连接中的祖先操作中检索到引用的行。
来自连接中祖先表的列可以被推送到下方,前提是它们满足前面列出的要求。以下是一个使用先前创建的表 t1
的此类查询示例
Press CTRL+C to copymysql> 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)