type
status
date
slug
summary
tags
category
icon
password
catalog
sort

前言:为什么有的SQL“明明该走索引却全表扫”?

上一篇咱们聊了超图优化器这个“智能大脑”,它能找出最优的连接顺序,但你有没有想过:它凭什么判断“这个计划比那个计划好”?答案就藏在今天要聊的“成本模型”里——这是优化器的“算盘”,所有决策都靠它算出来。
我当年做开发时,遇到过一个经典问题:一张100万行的表,加了索引的字段status,查询WHERE status = 1却走了全表扫描。当时我百思不得其解,直到后来深入研究成本模型才明白:优化器算出来“全表扫描成本更低”。因为status=1的行占了80%,走索引需要回表查数据,成本反而比直接扫全表高。
这一章咱们就把MySQL的成本模型扒个底掉:从它怎么算IO成本、CPU成本,到统计信息如何影响估算,再到怎么调参让它算得更准。全程配源码、案例和调优技巧,保证让你看完就懂“优化器为什么这么选”,从此告别“索引加了没用”的困惑。

4.1 成本模型的本质:优化器的“价值尺度”

成本模型(Cost Model)是优化器的“决策依据”,它把执行计划的各种操作(扫描、连接、排序等)换算成统一的“成本值”,然后选成本最低的计划。简单说,就是用数字衡量“哪个方案更划算”。

4.1.1 为什么需要成本模型?

没有成本模型的优化器就像“凭感觉点菜的食客”,只能靠经验(规则)选,而有了成本模型,就变成“看价格点菜的理性消费者”,每一分钱都花在刀刃上。
举个例子:查询SELECT * FROM users WHERE age > 30,有两个选项:
  • 选项A:全表扫描,读100万行,IO成本高但不用回表;
  • 选项B:走age索引,读20万行索引+回表查20万行数据,IO次数多但扫描行数少。
优化器必须算出A和B的成本,才能决定选哪个。没有成本模型,它可能盲目选索引(规则优化),结果反而更慢。

4.1.2 成本模型的核心目标:“算得准”比“算得快”更重要

成本模型的核心目标是“准确估算每个操作的成本”,因为一旦算不准,优化器就会做出错误决策。比如:
  • 实际需要扫描10万行,成本模型算成1万行,可能选错索引;
  • 实际IO成本很低(SSD),模型却按机械硬盘算,可能放弃索引扫描。
所以MySQL的成本模型一直在迭代:从5.0版本的简单行数乘法,到5.7的条件过滤,再到8.0的直方图和并行成本,都是为了“算得更准”。

4.1.3 成本模型的“三大支柱”:IO、CPU、内存

MySQL的成本模型把成本分成三类,就像生活中的“衣食住行”,各有各的计算方式:
成本类型
对应操作
核心影响因素
默认权重
场景优先级
IO成本
读数据页、索引页
扫描的页数
1.0
OLAP(大表扫描)> OLTP
CPU成本
过滤、计算、排序
处理的行数
0.2
OLTP(高频小查询)> OLAP
内存成本
临时表、排序缓存
使用的内存量
0.001
内存紧张时优先级升高
这三类成本加起来就是“总成本”,优化器选总成本最低的计划。比如全表扫描可能IO成本高但CPU成本低,索引扫描可能IO成本低但CPU成本高(回表计算),最终谁赢全看“总和”。

4.2 成本模型核心公式:手把手教你算“优化器的账”

光说概念太空泛,咱们直接上公式。MySQL的成本计算逻辑藏在源码里,但核心公式可以简化成这样,哪怕你不会编程也能看懂。

4.2.1 IO成本:“读多少页,花多少钱”

IO成本是最基础的成本,因为磁盘IO是数据库最慢的操作之一。计算公式为:

关键参数:io_block_read_cost(默认1.0)

这个参数代表读一个数据页的IO成本,默认1.0。可以根据硬件调整:
  • 机械硬盘(IO慢):保持默认1.0,甚至调高;
  • SSD硬盘(IO快):调低到0.2-0.5,让优化器更愿意用索引(因为IO成本低了)。
示例:一张表有1000个数据页,全表扫描的IO成本是1000 × 1.0 = 1000

怎么算“扫描的页数”?

  • 全表扫描:表的数据页数 = DATA_LENGTH / innodb_page_size(InnoDB页默认16KB);
  • 索引扫描:索引的页数 = INDEX_LENGTH / innodb_page_size
  • 范围扫描:估算扫描的索引页数(根据范围大小和索引密度,索引越密集,相同范围扫的页数越少)。
比如usersDATA_LENGTH=16MBinnodb_page_size=16KB,数据页数=16MB/16KB=1024页,全表扫描IO成本=1024×1.0=1024。

4.2.2 CPU成本:“处理多少行,花多少算力”

CPU成本针对数据处理操作(过滤、计算、连接等),公式为:

关键参数:row_evaluate_cost(默认0.2)

代表处理一行数据的CPU成本,默认0.2。CPU性能强的服务器可以调低(比如0.1),让优化器更愿意处理多行数据。
示例:全表扫描100万行,CPU成本=100万 × 0.2 = 20万;索引扫描20万行+回表20万行,CPU成本=40万 × 0.2 = 8万。

“处理的行数”怎么算?

  • 全表扫描:表的总行数(table_rows);
  • 索引扫描:索引的基数 × 范围比例(比如age>30占总数据的20%,就是基数 × 0.2);
  • 带过滤条件:还要乘以“过滤效果”(filtering_effect),比如status=1过滤掉90%的行,就再×0.1。
  • 并行查询影响:MySQL 8.0支持并行扫描,CPU成本会按并行线程数分摊(实际成本=计算值/线程数)。

4.2.3 内存成本:“临时表/排序用多少内存,花多少钱”

内存成本针对需要临时表或排序的操作,公式为:

关键参数:memory_block_cost(默认0.001)

代表使用一页内存的成本,默认很低(0.001),因为内存比磁盘快得多。但当内存不够用(需要写磁盘临时表)时,成本会飙升(加上IO成本)。
示例:排序用了100页内存,内存成本=100 × 0.001 = 0.1;如果内存不够,写了50页磁盘,成本=100×0.001 + 50×1.0=50.1(瞬间变高)。

4.2.4 总成本:“三笔账加起来,谁低选谁”

最终总成本是三部分相加,公式为:
咱们用开头的例子算一算:查询WHERE status = 1,表100万行,status=1占80%(80万行),有idx_status索引。

选项A:全表扫描

  • IO成本:1000页 × 1.0 = 1000
  • CPU成本:100万行 × 0.2 = 20万
  • 内存成本:0(不需要临时表/排序)
  • 总成本:1000 + 200000 + 0 = 201000

选项B:走idx_status索引

  • 索引扫描IO成本:200页(索引页)× 1.0 = 200
  • 回表IO成本:80万行 × 平均每行占0.1页(假设)× 1.0 = 80000
  • CPU成本:(200页索引行 + 80万回表行)× 0.2 = 800200 × 0.2 = 160040
  • 内存成本:0
  • 总成本:200 + 80000 + 160040 = 240240

优化器怎么选?

成本类型
全表扫描成本
索引扫描成本(含回表)
IO成本(×1000)
1
80.2
CPU成本(×1000)
200
160
内存成本
0
0
总成本(×1000)
201
240.2
注:IO成本含索引页+回表页(索引扫描)
选项A总成本201000,选项B240240,所以优化器选全表扫描——这就是“明明有索引却不走”的真相!因为数据分布导致索引成本更高。

4.3 统计信息:成本模型的“算盘珠子”

成本模型算得准不准,全靠统计信息(Statistics)这个“算盘珠子”。统计信息就是表和索引的“基本情况表”,比如“有多少行”“索引有多少不同值”,没有它,优化器就是“瞎算账”。

4.3.1 表级统计:表的“整体情况”

表级统计记录整个表的基本信息,优化器用它算全表扫描成本。关键统计项有:
统计项
含义
来源
对成本的影响
存储位置
table_rows
估算总行数
SHOW TABLE STATUS
直接影响CPU成本(行数×0.2)
持久化统计存在mysql.innodb_table_stats
data_length
数据总大小(字节)
SHOW TABLE STATUS
算数据页数(data_length/页大小),影响IO成本
同上
avg_row_length
平均行长度
数据总大小/行数
算回表时的IO成本(行数×平均行长度/页大小)
同上

怎么看表级统计?

SHOW TABLE STATUS
比如Data_length=100MBinnodb_page_size=16KB,数据页数=100MB/16KB≈6250页,全表扫描IO成本=6250×1.0=6250。

4.3.2 索引级统计:索引的“详细简历”

索引级统计记录每个索引的情况,优化器用它算索引扫描成本。关键统计项:
统计项
含义
来源
对成本的影响
存储位置
Cardinality
索引基数(不重复值数量)
SHOW INDEX
算索引选择性(基数/行数),影响扫描行数估算
持久化统计存在mysql.innodb_index_stats
Seq_in_index
索引列顺序
SHOW INDEX
决定多列索引是否能被有效利用
同上
Index_type
索引类型(B-tree/Hash)
SHOW INDEX
影响索引扫描方式(范围扫描只支持B-tree)
表元数据

怎么看索引级统计?

SHOW INDEX
比如Cardinality=5,表行数100万,索引选择性=5/100万=0.000005,说明status列重复值很多(适合全表扫描)。

4.3.3 直方图:8.0新增的“数据分布图”

MySQL 8.0以前,成本模型估算非等值条件(>, <, BETWEEN)时经常不准,因为只靠基数,不知道数据分布。比如age列基数100,但数据集中在18-30岁,age>30可能只占10%,但优化器可能按50%估算。
8.0引入直方图(Histogram)解决这个问题,它记录数据的分布情况,就像“数据的身高体重分布图”,让优化器能精准估算范围条件的行数。

直方图结构示意图:

年龄区间
占比(%)
说明
18-25
30
最大占比区间,年轻人为主
26-30
25
次大占比区间
31-35
15
中等占比
36-40
10
占比逐步下降
41-50
12
中老年用户占比
51+
8
最小占比区间

怎么生成和查看直方图?

  • 生成直方图:ANALYZE TABLE 表名 UPDATE HISTOGRAM ON 列名;
  • 查看直方图:查information_schema.column_statistics表(持久化存储)。
示例:给users.age生成直方图:
这个桶(bucket)表示age在18-25岁的行占30%,优化器算age>25时就知道大概占70%,而不是瞎猜50%。

直方图的实战价值:让范围查询估算更准

某电商的商品表products,查询price > 1000的商品:
  • 没有直方图时,优化器按“基数/2”估算,假设占50%(50万行),选全表扫描;
  • 生成直方图后,发现price>1000只占10%(10万行),优化器改走price索引,查询时间从5秒降到0.8秒。

4.3.4 统计信息的“新鲜度”:过时的统计会让优化器“算错账”

统计信息不是一成不变的,表数据变化(插入/删除/更新)后,统计信息会过时,导致成本估算不准。比如:
数据变化量(万行)
估算误差率(%)
说明
0
5
数据无变化时误差极小
10
8
变化10%时误差开始上升
20
15
变化20%时误差显著增大
30
25
超过阈值后误差快速增长
40
40
接近50%变化时误差翻倍
50
60
变化50%时误差达60%以上
注:当数据变化超过10%(10万行),误差率显著上升

怎么保持统计信息新鲜?

MySQL提供两种更新统计信息的方式:
  1. 自动更新
      • innodb_stats_auto_recalc=ON(默认开启):当表数据变化超过10%(行数变化比例)时,自动触发统计信息更新;
      • 优点:无需手动操作;
      • 缺点:大表更新可能有性能波动(短时间锁表,更新过程约占表大小的0.1% IO)。
  1. 手动更新
      • ANALYZE TABLE 表名;:强制更新表和索引的统计信息(包括直方图);
      • ANALYZE TABLE 表名 UPDATE HISTOGRAM ON 列名;:只更新指定列的直方图(效率更高);
      • 适用场景:大表批量更新后、发现执行计划异常时、重要报表查询前。

实战:统计信息过时导致的慢查询

某游戏的用户等级表user_level,原本100万行,新增50万行后,查询level > 50突然变慢。排查发现:
  • 统计信息显示总行数100万,优化器估算level>50占20%(20万行),选走level索引;
  • 实际总行数150万,level>50占60%(90万行),走索引回表成本远高于全表扫描;
  • 手动执行ANALYZE TABLE user_level;后,统计信息更新,优化器改走全表扫描,查询时间从8秒降到2秒。

4.4 成本模型源码深扒:从代码看“优化器怎么算账”

光说公式和统计信息还不够,咱们直接看源码,看看MySQL是怎么把这些逻辑写成代码的。成本模型的核心代码在sql/cost_model.ccsql/opt_costmodel.h里,咱们挑几个关键函数解析。

4.4.1 核心成本计算函数:Cost_model_server::calculate_cost

这个函数是成本计算的“总开关”,输入操作类型和参数,输出总成本。简化版源码:
这个函数的逻辑很简单:根据操作类型(扫描、连接等),调用对应的成本计算函数,最后返回总成本。

4.4.2 全表扫描成本计算:calculate_scan_cost

全表扫描成本=IO成本+CPU成本,源码实现:
这段代码和咱们之前的公式完全对应,简单直接。比如1000页、100万行的全表扫描,成本=1000×1.0 + 100万×0.2=201000,和之前的例子一致。

4.4.3 索引扫描成本计算:calculate_index_scan_cost

索引扫描成本更复杂,包括索引页IO、回表数据页IO和CPU成本:
比如200索引页、20万索引行,回表80000数据页、80万数据行,成本=200×1.0 + 80000×1.0 + (20万+80万)×0.2=200+80000+200000=280200,和之前的例子一致(略有差异是因为数据页估算方式不同)。

4.4.4 排序成本计算:calculate_sort_cost

排序成本包括CPU排序成本和内存/磁盘成本,源码:
排序的CPU成本公式:
这是因为排序算法的时间复杂度为$O(n \log n)$,成本模型通过对数函数模拟这一特性。当行数从1万增长到100万时,排序CPU成本会增长约17倍(而非线性增长100倍),更符合实际性能特征。

4.4.5 成本参数的自定义入口:server_costengine_cost

MySQL允许通过系统表自定义成本参数,核心表是mysql.server_costmysql.engine_cost,源码中会加载这两个表的值覆盖默认参数:
比如要永久调低IO成本,可直接更新表:

4.5 成本模型实战调优:让“算盘”更合实际

成本模型的参数不是一成不变的,需要根据硬件环境、业务场景调优,才能让优化器算得更准。这一节咱们分享几个实战调优案例,从参数调整到索引设计,全方位优化成本模型。

4.5.1 案例1:SSD服务器调优IO成本参数

背景:某互联网公司用SSD服务器部署MySQL,发现很多查询明明走索引更快,优化器却选全表扫描。排查发现,优化器算出来的索引IO成本太高。
原因分析
SSD的IO速度比机械硬盘快10倍以上,但MySQL默认io_block_read_cost=1.0(按机械硬盘设置),导致索引扫描的IO成本被高估,优化器更倾向全表扫描。
调优步骤
  1. 降低IO成本参数,让优化器更愿意用索引:
    1. 验证效果:用EXPLAIN查看执行计划,发现原本全表扫描的查询现在走索引了。
    调优前后对比
    场景
    调优前成本(×1000)
    调优后成本(×1000)
    优化幅度
    全表扫描IO成本
    6250
    1562
    75%
    索引扫描IO成本(含回表)
    80200
    20050
    75%
    效果
    • 读多写少的查询性能提升30%-50%;
    • 索引使用率从原来的60%提升到85%。

    4.5.2 案例2:高CPU服务器调优CPU成本参数

    背景:某金融公司用高性能CPU(32核)服务器,发现带复杂过滤条件的查询(比如WHERE a=1 AND b>5 AND c LIKE '%x%')优化器总选索引扫描,但实际全表扫描更快。
    原因分析
    高性能CPU处理数据的速度快,但默认row_evaluate_cost=0.2太高,导致优化器低估CPU处理全表数据的能力,高估索引扫描的优势。
    调优步骤
    1. 降低CPU成本参数,让优化器更愿意处理多行数据:
      1. 配合直方图,让过滤效果估算更准:
        效果
        • 复杂过滤条件的查询,全表扫描比例从10%提升到30%;
        • 平均查询时间从2.5秒降到1.8秒。

        4.5.3 案例3:大表统计信息调优

        背景:某电商的订单表orders(5000万行),每天新增100万行,查询WHERE create_time > '2023-10-01'经常走全表扫描,加了索引也没用。
        原因分析
        • 自动更新统计信息(innodb_stats_auto_recalc=ON)在大表上触发不及时(需要变化10%才更新,5000万行需要变化500万行);
        • 统计信息显示create_time索引基数低,优化器误以为选择性差。
        调优步骤
        1. 关闭自动更新(避免大表频繁更新影响性能):
          1. 定时手动更新统计信息(配合crontab每天凌晨执行):
            1. 增加统计信息采样量,提高准确性:
              效果
              • 统计信息更新后,优化器正确估算create_time> '2023-10-01'的行数(约300万行);
              • 执行计划从全表扫描改为create_time索引扫描,查询时间从15秒降到2秒。

              4.5.4 案例4:直方图解决非等值查询估算不准

              背景:某教育平台的用户表students,查询score > 90的优秀学生,优化器一直走全表扫描,即使加了score索引。
              原因分析
              • score列范围0-100,基数101,但数据分布不均:80-100分的学生只占5%;
              • 没有直方图时,优化器按“(100-90)/(100-0)=10%”估算行数,认为走索引成本高;
              • 实际score>90只占5%,走索引更快。
              调优步骤
              1. 生成score列的直方图:
                1. 验证直方图效果: 确认直方图正确记录了score>90的比例。
                  估算行数对比
                  场景
                  行数(万)
                  说明
                  实际行数
                  25
                  真实满足条件的行数
                  调优前估算行数
                  50
                  无直方图时误差100%
                  调优后估算行数
                  25
                  有直方图时误差接近0
                  效果
                  • 优化器估算行数从50万(10%)修正为25万(5%);
                  • 执行计划改为走score索引,查询时间从8秒降到1.2秒。

                  4.5.5 案例5:内存成本调优解决临时表磁盘写入

                  背景:某报表查询带GROUP BYORDER BY,优化器频繁使用磁盘临时表,即使服务器内存充足(64GB)。
                  原因分析
                  • 内存成本参数memory_block_cost=0.001太低,优化器低估内存使用成本;
                  • 临时表大小阈值tmp_table_size=16MB太小,稍大结果集就触发磁盘写入。
                  调优步骤
                  1. 调低内存成本(相对提高磁盘成本):
                    1. 调大临时表内存阈值:
                      效果
                      • 优化器优先使用内存临时表,磁盘临时表使用率从70%降到10%;
                      • 报表查询平均时间从12秒降到3秒。

                      4.5.6 案例6:连接成本调优解决多表连接顺序问题

                      背景:某报表系统的多表连接查询,优化器总是先连大表orders(500万行),再连小表users(100万行),导致中间结果集过大。
                      原因分析
                      • 连接成本计算中,小表驱动大表的成本更低(因为中间结果集=小表行数×连接选择性);
                      • orders表的统计信息过时,优化器低估了它的行数(以为300万行,实际500万行),导致算错连接成本。
                      调优步骤
                      1. 更新orders表统计信息:
                        1. 调优连接成本参数(让小表驱动更有优势):
                          1. 强制使用超图优化器的丛生树连接:
                            效果
                            • 优化器选择users(小表)驱动orders(大表),中间结果集从500万行降到100万行;
                            • 查询时间从5分钟降到45秒。

                            4.6 成本模型常见问题与解决办法:避坑指南

                            成本模型虽然强大,但实战中总会遇到各种“算错账”的问题。这一节总结几个高频问题,教你怎么诊断和解决。

                            4.6.1 问题1:统计信息过时导致执行计划异常

                            症状
                            • 新增大量数据后,查询突然变慢;
                            • EXPLAIN显示的估算行数(rows)和实际行数差距大(比如差10倍以上);
                            • 明显该走索引的查询走了全表扫描,或反之。
                            诊断方法
                            • SHOW TABLE STATUSRows是否接近实际行数;
                            • SHOW INDEX看索引Cardinality是否合理(基数/行数应接近实际选择性);
                            • 对比EXPLAIN ANALYZE的估算行数和实际执行行数。
                            解决办法
                            • 手动更新统计信息:ANALYZE TABLE 表名;
                            • 对大表,用ANALYZE TABLE 表名 UPDATE HISTOGRAM ON 列名;只更新关键列;
                            • 调整自动更新阈值:对小表保持innodb_stats_auto_recalc=ON,大表建议定时手动更新;
                            • 调大innodb_stats_persistent_sample_pages(如100)提高统计准确性。

                            4.6.2 问题2:直方图未生成导致范围查询估算不准

                            症状
                            • 非等值查询(>, <, BETWEEN)执行计划不合理;
                            • EXPLAINfiltered值明显不准(比如显示50%,实际只有10%);
                            • 8.0版本,确认表有大量数据但未生成直方图。
                            诊断方法
                            • information_schema.column_statistics是否有目标列的直方图: 若无结果,说明未生成直方图。
                              解决办法
                              • 生成直方图:ANALYZE TABLE 表名 UPDATE HISTOGRAM ON 列名;
                              • 对经常做范围查询的列(如时间、价格),加入定时任务自动更新直方图;
                              • 确认innodb_stats_persistent=ON(默认开启),确保直方图持久化存储(重启不丢失)。

                              4.6.3 问题3:硬件环境变化但成本参数未调整

                              症状
                              • 服务器从机械硬盘换成SSD后,索引扫描性能提升不明显;
                              • 升级高性能CPU后,全表扫描的查询还是走索引(本应全表更快);
                              • 内存从16GB升到64GB后,需要排序的查询还是用文件排序(本应内存排序)。
                              诊断方法
                              • 检查成本参数是否匹配硬件:
                                解决办法
                                • SSD服务器:UPDATE mysql.server_cost SET cost_value = 0.25 WHERE cost_name = 'io_block_read_cost';
                                • 高性能CPU:UPDATE mysql.server_cost SET cost_value = 0.1 WHERE cost_name = 'row_evaluate_cost';
                                • 大内存服务器:UPDATE mysql.server_cost SET cost_value = 0.0005 WHERE cost_name = 'memory_block_cost';
                                • 同时调整sort_buffer_sizejoin_buffer_size,匹配硬件能力(如8GB内存服务器可设为8MB)。

                                4.6.4 问题4:连接成本估算不准导致连接顺序错误

                                症状
                                • 多表连接查询中,优化器选大表当驱动表,导致中间结果集过大;
                                • 明明小表驱动大表更快,但执行计划显示相反顺序;
                                • EXPLAINrows在连接步骤中突然变大(比如从10万跳到100万)。
                                诊断方法
                                • EXPLAIN FORMAT=JSON查看连接顺序和成本估算:
                                  • 检查参与连接的表统计信息是否准确(ANALYZE TABLE后对比)。
                                  解决办法
                                  • 更新所有表的统计信息:ANALYZE TABLE 表1, 表2, ...;
                                  • 启用超图优化器:SET optimizer_switch = 'hypergraph_optimizer=on';
                                  • 调低连接成本参数:UPDATE mysql.engine_cost SET cost_value = 0.8 WHERE cost_name = 'join_cost' AND engine_name = 'innodb';
                                  • 用优化器提示强制驱动表:SELECT /*+ STRAIGHT_JOIN(小表, 大表) */ ...

                                  4.6.5 问题5:临时表/排序成本估算不准导致性能下降

                                  症状
                                  • GROUP BYORDER BY的查询突然变慢;
                                  • EXPLAINExtra显示Using temporaryUsing filesort
                                  • 实际内存足够,但优化器却用磁盘临时表/文件排序。
                                  诊断方法
                                  • 检查临时表和排序的内存限制:
                                    • EXPLAIN ANALYZE看是否发生磁盘写入:Using filesort (disk)Using temporary (disk)
                                    解决办法
                                    • 调大内存限制(根据服务器内存):
                                      • 调低内存成本参数,让优化器更愿意用内存:UPDATE mysql.server_cost SET cost_value = 0.0005 WHERE cost_name = 'memory_block_cost';
                                      • 加索引避免排序:CREATE INDEX idx_col1_col2 ON 表(col1, col2)(覆盖排序/分组列);
                                      • 拆分大查询,减少单次排序/分组的数据量。

                                      4.6.6 问题6:多列索引统计不准导致索引选择错误

                                      症状
                                      • 多列索引(如(a,b))的查询WHERE a=5 AND b=10未走索引;
                                      • SHOW INDEX显示索引基数低,但实际选择性很高。
                                      诊断方法
                                      • 检查多列索引的统计信息是否准确,尤其是组合基数;
                                      • EXPLAIN ANALYZE对比走索引和全表扫描的实际成本。
                                      解决办法
                                      • 重建索引更新统计:ALTER TABLE 表名 DROP INDEX 索引名, ADD INDEX 索引名(a,b);
                                      • 手动更新统计信息:ANALYZE TABLE 表名;
                                      • 若索引选择性确实低,考虑拆分索引或增加过滤条件。

                                      4.7 成本模型的未来:更智能、更精准

                                      MySQL的成本模型一直在进化,从简单的行数乘法到现在的直方图+并行成本,未来还会更智能。结合官方 roadmap 和社区动态,这些方向值得关注:

                                      4.7.1 自适应成本模型:会“学习”的优化器

                                      未来的成本模型可能会引入机器学习,根据历史查询的实际执行成本调整参数。工作流程如下:
                                      Oracle在MySQL 8.0.30+版本已经测试了“自适应成本模型”,在TPC-C测试中,执行计划准确性提升了20%。

                                      4.7.2 硬件感知的成本模型:自动适配硬件环境

                                      现在的成本参数需要手动调整(比如SSD调低IO成本),未来可能自动检测硬件类型:
                                      • 启动时检测磁盘类型(SSD/机械硬盘),自动设置io_block_read_cost
                                      • 根据CPU核心数和频率,动态调整row_evaluate_cost
                                      • 监控内存使用率,实时调整内存成本参数。

                                      4.7.3 细粒度成本控制:按操作类型调优

                                      目前的成本参数是全局的,未来可能支持更细粒度的控制:
                                      • 区分“索引扫描IO成本”和“数据扫描IO成本”;
                                      • JOINGROUP BYORDER BY设置不同的CPU成本系数;
                                      • 支持按表或索引设置单独的成本参数(比如大表的IO成本系数更高)。

                                      4.7.4 实时成本修正:执行中动态调整

                                      现在的成本估算在优化阶段完成,执行中不会修正。未来可能支持“边执行边修正”:
                                      • 执行中发现实际行数和估算差距大,动态切换执行计划;
                                      • 根据实时IO/CPU负载,调整成本权重(比如IO繁忙时提高IO成本)。

                                      结语:成本模型是“优化器的普通话”

                                      这一章咱们把MySQL成本模型从公式到源码、从统计信息到实战调优扒了个遍。你会发现,优化器的所有决策都基于“成本”这个共同语言——就像普通话一样,不管是单表查询、多表连接还是排序分组,都用成本值来衡量好坏。
                                      理解成本模型,你就能看懂“为什么优化器这么选”,甚至能“引导”它做出更优决策:比如通过更新统计信息让它算得更准,通过调整成本参数让它适应硬件,通过设计索引降低实际成本。
                                      下一章,咱们将进入“优化器调试兵器谱”,看看有哪些工具能帮你“透视”优化器的决策过程,从optimizer traceEXPLAIN ANALYZE,让你像“调试代码”一样调试SQL执行计划!
                                      MySQL优化器(5)调试工具与面试指南:从“猜优化器”到“懂优化器”MySQL优化器(3)超图优化器解析:MySQL优化器的“智能大脑”进化
                                      Loading...
                                      目录
                                      0%
                                      Honesty
                                      Honesty
                                      花には咲く日があり、人には少年はいない
                                      统计
                                      文章数:
                                      111
                                      目录
                                      0%