MySQL optimizer_switch参数之condition_fanout_filter开关

2024年 1月 30日 44.9k 0

1、官网介绍

Condition Filtering Flags
condition_fanout_filter (default on)
Controls use of condition filtering.
For more information, see Section 8.2.1.13, “Condition Filtering”.

condition_fanout_filter 默认值为on
可通过命令 select @@optimizer_switch 查看
我们都知道在多表联连中MySQL通常都选用小表做为驱动表
如果condition_fanout_filter = off 则只考虑引擎级别索引树的过滤 即explain的rows 用于多表关联行数的估计,谁是小表。
如果condition_fanout_filter = on 则考虑的是引擎级别的过滤 再 * server层的过虑。即 explain中的 rows*filterd /100 为最终行数

在官网中有详细的介绍,可移步这里查看

由于默认为on 即在多表关联中要考虑filterd来确认谁是驱动表,但有时候也因为这个特性,让MySQL走错误的执行计划,下面介始我在生产中遇到的一个实例

2、生产实例

由于已经给研发同学上过5堂性能优化的课了,对于普通语句研发同学都能优化了,下述语句研发同学知道用指定驱动表hint方式优化。但研发问我。MySQL为什么这么傻,总是选错驱动表,我就和他们说说大概的原理,并写一篇小文以做记录。

有如下语句

SELECT
COUNT(*)
FROM erp_bill_finance_voucher a
INNER JOIN erp_bill_index bi ON bi.`billid`=a.`billid` AND bi.profileid=a.profileid AND bi.billtype=905
WHERE a.profileid=200004255 AND a.billdate >= '2023-11-15' AND bi.billdate >= '2023-11-15'
AND a.billdate < '2024-01-16' AND bi.billdate < '2024-01-16' AND a.ifred = 0

执行计划如下

表a的where 条件中都没有索引 但表bi是有的。
由于 condition_fanout_filter = on 所以a表mysql 估算的最终行数为 rows*filterd /100
即 1003026 *0.56/100.00 = 5616 行

但由于a表全表扫描了 1003026 导致此SQL执行较慢

我将 condition_fanout_filter关闭

EXPLAIN
SELECT
/*+ set_var(optimizer_switch='condition_fanout_filter=off') */
COUNT(*)
FROM erp_bill_finance_voucher a
INNER JOIN erp_bill_index bi ON bi.`billid`=a.`billid` AND bi.profileid=a.profileid AND bi.billtype=905
WHERE a.profileid=200004255 AND a.billdate >= '2023-11-15' AND bi.billdate >= '2023-11-15'
AND a.billdate < '2024-01-16' AND bi.billdate < '2024-01-16' AND a.ifred = 0

但第二个的性能比第一个提升一倍
我实际生产中的语句 where 条件与join表都更多。提升更明细。有5倍左右的性能提升。

上述语句还有一个优化方式就是指定驱动表

EXPLAIN
SELECT
/*+ join_prefix(bi) */
COUNT(*)
FROM erp_bill_finance_voucher a
INNER JOIN erp_bill_index bi ON bi.`billid`=a.`billid` AND bi.profileid=a.profileid AND bi.billtype=905
WHERE a.profileid=200004255 AND a.billdate >= '2023-11-15' AND bi.billdate >= '2023-11-15'
AND a.billdate < '2024-01-16' AND bi.billdate < '2024-01-16' AND a.ifred = 0


通过 join_prefix hint 指定bi为驱动表
有关join_order 相关的hint 我以前专门写过,可点这里查看

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论