15.MySQL优化Condition Filtering

介绍

在连接处理中,前缀行是从连接中的一个表传递到下一个表的那些行。通常,优化器尝试在连接顺序的早期放置具有低前缀计数的表,以保持行组合的数量不会快速增加。在某种程度上,优化器可以利用一些条件信息查询表中需要的行传递给下一个,它可以更准确地计算行估计并选择最佳执行计划。

假如没有条件过滤,表的前缀行数是基于各种优化器的访问方法根据Where条件进行的估量估计。Condition filtering使优化器能够使用WHERE访问方法未考虑的子句中的其他相关条件 ,从而改进其前缀行计数估计。例如,可能存在可用于从连接中的当前表中选择行的基于索引的访问方法,但在该表中可能还存在其他条件。WHERE 可以过滤(进一步限制)传递给下一个表的合格行的估计的子句。

只有在以下情况下,条件才会影响过滤估算:

  • 条件过滤指的是当前表
  • 它取决于连接序列中早期表的常量值或值。
  • 它不考虑已经存在的访问方法

在EXPLAIN输出中,rows列指示所选访问方法的行估计值,该filtered 列反映条件筛选的效果。 filtered值以百分比表示。最大值为100,这意味着不会对行进行过滤。值从100开始减少表示过滤量增加。

前缀行计数(估计从连接中的当前表传递到下一个的行数)是rows和 filtered值的乘积。也就是说,前缀行计数是估计的行计数,通过估计的过滤效果减少。例如,如果rows是1000并且filtered是20%,则条件过滤将估计的行数1000减少到前缀行计数1000×20%= 1000×.2 = 200。

请考虑以下查询:

SELECT *
  FROM employee JOIN department ON employee.dept_no = department.dept_no
  WHERE employee.first_name = 'John'
  AND employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01';

假设数据集具有以下特征:

  • 该employee表有1024行。

  • 该department表有12行。

  • 两个表都有一个索引dept_no。

  • 该employee表有一个索引 first_name。

  • 8行满足这个条件 employee.first_name:

      employee.first_name = 'John'
    
  • 150行符合以下条件 employee.hire_date:

      employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01'
    
  • 1行满足两个条件:

      employee.first_name = 'John'
      AND employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01'
    

没有条件过滤, EXPLAIN产生如下输出:

+----+------------+--------+------------------+---------+---------+------+----------+
| id | table      | type   | possible_keys    | key     | ref     | rows | filtered |
+----+------------+--------+------------------+---------+---------+------+----------+
| 1  | employee   | ref    | name,h_date,dept | name    | const   | 8    | 100.00   |
| 1  | department | eq_ref | PRIMARY          | PRIMARY | dept_no | 1    | 100.00   |
+----+------------+--------+------------------+---------+---------+------+----------+

因为employee,name索引上的访问方法会 获取与名称匹配的8行’John’。没有进行过滤(filtered是100%),因此所有行都是下一个表的前缀行:前缀行计数为 rows× filtered= 8×100%= 8。

通过条件过滤,优化器还考虑WHERE了访问方法未考虑的子句中的条件。在这种情况下,优化器使用试探法来估计所述的BETWEEN的条件下employee.hire_date过滤效果为16.31%。结果,EXPLAIN产生如下输出:

+----+------------+--------+------------------+---------+---------+------+----------+
| id | table      | type   | possible_keys    | key     | ref     | rows | filtered |
+----+------------+--------+------------------+---------+---------+------+----------+
| 1  | employee   | ref    | name,h_date,dept | name    | const   | 8    | 16.31    |
| 1  | department | eq_ref | PRIMARY          | PRIMARY | dept_no | 1    | 100.00   |
+----+------------+--------+------------------+---------+---------+------+----------+

现在前缀行计数为rows× filtered= 8×16.31%= 1.3,这更接近地反映了实际数据集。

通常,优化器不会计算最后一个连接表的条件过滤效果(前缀行数减少),因为没有下一个表要传递行。

如果优化器过高估计条件过滤的影响,则性能可能比不使用条件过滤时更差。在这种情况下,这些技术可能有所帮助:

  • 如果未对列建立索引,请对其进行索引,以便优化程序具有有关列值分布的一些信息,并可以改进其行估计值。

  • 同样,如果没有可用的列直方图信息,则生成直方图(参见 第8.9.6节“优化程序统计”)。

  • 更改连接顺序。完成此操作的方法包括连接顺序优化器提示(请参见 第8.9.2节“优化程序提示”), STRAIGHT_JOIN紧跟在 SELECT和 STRAIGHT_JOIN连接运算符之后。

  • 禁用会话的条件筛选:

      SET optimizer_switch = 'condition_fanout_filter=off';
    
  • 或者,对于给定查询,使用优化程序提示:

      SELECT /*+ SET_VAR(optimizer_switch = 'condition_fanout_filter=off') */
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值