当前位置: 首页 > news >正文

MySQL查询优化器的成本模型:从统计信息到执行计划选择的内幕

MySQL查询优化器的成本模型:从统计信息到执行计划选择的内幕

一、InnoDB统计信息的双轨制

MySQL优化器做出执行计划决策的基础是统计信息。InnoDB提供两种统计信息模式:持久化统计信息(innodb_stats_persistent=ON,默认)和非持久化统计信息。两者的行为差异直接影响执行计划的稳定性。

持久化统计信息存储在mysql.innodb_table_statsmysql.innodb_index_stats表中,服务器重启后依然保留。非持久化统计信息只在内存中,每次重启后需要ANALYZE TABLE重新收集。

控制持久化统计信息的关键参数:

参数默认值含义
innodb_stats_persistent_sample_pages20持久化统计的采样页面数
innodb_stats_auto_recalcON表变更10%后自动重新计算
innodb_stats_persistentON是否使用持久化统计
innodb_stats_transient_sample_pages8非持久化统计的采样页面数

二、Cardinality估算与索引选择

Cardinality(基数)是索引区分度的度量——表示索引列中不同值的估计数量。优化器使用Cardinality来判断使用哪个索引能过滤掉最多的行。

-- 查看表的统计信息 SELECT database_name, table_name, n_rows, clustered_index_size / 1024 AS ibd_size_mb FROM mysql.innodb_table_stats WHERE database_name = 'order_db' AND table_name = 'orders'; -- 查看索引的Cardinality估算 SELECT database_name, table_name, index_name, stat_name, -- n_diff_pfxNN: 前NN列的不同值数量 stat_value, stat_description, sample_size FROM mysql.innodb_index_stats WHERE database_name = 'order_db' AND table_name = 'orders' ORDER BY index_name, stat_name;

Cardinality估算采用随机采样方式——InnoDB随机读取若干个索引页面,根据这些页面中的值分布推算整体基数。采样页面越多,估算越准确,但收集成本越高。这导致一个经典问题:统计信息漂移——随着数据增长,旧的统计信息不再反映真实分布。

一个典型的生产案例:订单表按月分区,每月新增500万条记录。月初统计信息显示order_status='pending'约占5%,执行计划使用该索引。但到月底pending状态实际已占30%,全表扫描反而更快。优化器因为使用旧的统计信息,仍然选择索引扫描,导致查询从50毫秒退化到5秒。

-- 强制更新统计信息 ANALYZE TABLE order_db.orders; -- 查看执行计划中的rows估算偏差 EXPLAIN FORMAT=JSON SELECT * FROM order_db.orders WHERE order_status = 'pending' AND create_time > '2026-07-01';

三、成本常数的含义与影响

MySQL优化器使用成本模型来比较不同执行计划的代价。成本单位并非物理时间,而是一个抽象的度量——由两个核心常数定义:

-- 查看成本模型参数(MySQL 5.7+) SELECT * FROM mysql.server_cost; -- row_evaluate_cost: 0.2 —— 评估一行记录的代价 -- memory_temptable_create_cost: 2.0 -- memory_temptable_row_cost: 0.2 SELECT * FROM mysql.engine_cost WHERE engine_name = 'InnoDB'; -- io_block_read_cost: 1.0 —— 从磁盘随机读取一个页面的代价 -- memory_block_read_cost: 0.5 —— 从内存读取一个页面的代价

io_block_read_costrow_evaluate_cost是成本模型的两大支柱。全表扫描的成本 = IO读取代价 × 页面数 + 行评估代价 × 行数。索引扫描的成本 = IO读取代价 × 索引页面数 + 行评估代价 × 估计行数 + 回表IO代价。

理解这些常数有助于解释优化器的"反常"决策。例如当row_evaluate_cost为0.2时,扫描100万行的评估成本是20万单位;但如果在机械硬盘上随机读取100万行数据的IO成本远超索引读取。这就是为什么在SSD上优化器更倾向于全表扫描——io_block_read_cost实际上降低了。

""" MySQL成本模型的简化实现,展示执行计划选择的内部逻辑 """ from dataclasses import dataclass @dataclass class CostConstants: io_block_read_cost: float = 1.0 memory_block_read_cost: float = 0.5 row_evaluate_cost: float = 0.2 key_compare_cost: float = 0.1 @dataclass class TableStats: total_rows: int data_pages: int page_size: int = 16384 # 16KB @dataclass class IndexStats: name: str cardinality: int # 不同值的估计数量 pages: int # 索引占用页面数 is_clustered: bool = False class OptimizerCostModel: """MySQL优化器成本模型简化版""" def __init__(self, constants: CostConstants = CostConstants()): self.c = constants def table_scan_cost(self, stats: TableStats) -> float: """全表扫描成本""" io_cost = stats.data_pages * self.c.io_block_read_cost cpu_cost = stats.total_rows * self.c.row_evaluate_cost return io_cost + cpu_cost def index_lookup_cost( self, table: TableStats, index: IndexStats, selectivity: float ) -> float: """ 索引查找成本 Args: selectivity: 过滤选择率 (0.0 ~ 1.0) """ estimated_rows = int(table.total_rows * selectivity) # B+树搜索成本:log2(索引基数) × key_compare_cost tree_traversal = ( __import__('math').log2(max(index.cardinality, 1)) * self.c.key_compare_cost ) # 索引页扫描成本 pages_to_read = int(index.pages * selectivity) + 1 index_io = pages_to_read * self.c.io_block_read_cost # 回表成本(聚簇索引无回表成本) if index.is_clustered: row_fetch_cost = 0 else: # 每条符合条件的记录一次随机IO(估算) row_fetch_cost = estimated_rows * self.c.io_block_read_cost cpu_cost = estimated_rows * self.c.row_evaluate_cost return tree_traversal + index_io + row_fetch_cost + cpu_cost

四、优化器Trace的分析方法

当执行计划不符合预期时,优化器Trace是定位问题的利器。它能展示优化器考虑了哪些候选计划、各计划的成本是多少、最终为何选择了某个方案。

-- 开启优化器Trace SET optimizer_trace="enabled=on"; SET optimizer_trace_max_mem_size=1000000; -- 执行目标查询 SELECT o.order_id, o.user_id, o.amount, o.status FROM orders o JOIN order_items oi ON o.order_id = oi.order_id WHERE o.user_id = 12345 AND o.create_time > '2026-06-01'; -- 获取Trace SELECT trace FROM information_schema.optimizer_trace LIMIT 1\G -- 分析完成后关闭Trace SET optimizer_trace="enabled=off";

Trace输出包含几个关键部分:

  • considered_execution_plans:所有被评估的执行计划
  • rows_estimation:每个表的行数估算过程
  • attached_conditions_summary:条件下推情况
  • cost_of_plan:最终选择的计划的成本分解

常见的问题模式:"range_scan_alternatives"中出现了"chosen": false而你期望使用该索引,说明Cost估算使优化器认为全表扫描更优。这时需要检查索引Cardinality是否准确,或者row_evaluate_cost是否需要调整。

五、总结

MySQL优化器的成本模型本质上是统计信息加成本常数的函数。Cardinality估算的准确性直接决定索引选择的正确性——而采样机制天然存在偏差风险。理解io_block_read_costrow_evaluate_cost这两个魔法数字,能帮助你解释为什么优化器在SSD和HDD上的行为截然不同。优化器Trace是解决"为什么走这个索引"问题的终极工具,它把黑盒决策变成了白盒可追溯的过程。统计信息不准确时的标准处理流程是:ANALYZE TABLE → 检查执行计划变化 → 如果统计信息刷新后仍不理想,考虑使用Hint或调整成本常数。

http://www.jsqmd.com/news/1207586/

相关文章:

  • BepInEx:让Unity游戏焕发新生的插件框架全解析
  • 3Blue1Brown数学动画制作终极指南:从零开始创建专业数学可视化
  • 如何将 selene 集成到 CI/CD 流程中:自动化 Lua 代码质量检查
  • 如何用Python和Manim库制作专业级数学动画:3Blue1Brown视频制作完整指南
  • 【小程序毕业设计】轻量化同城分类信息服务小程序的设计与实现 基于 SpringBoot 的校园综合信息分类服务平台(源码+文档+远程调试,全bao定制等)
  • GitHub_Trending/i/i投资者关系:域名项目融资进展报告
  • 如何快速迁移OneNote笔记:终极格式转换器使用指南
  • 动态规划算法实战解析,电梯调度与坦克作战的代码实现思路
  • 自动绕线机价格多少钱?变压器 数控 精密 光纤 医疗线圈绕线机影响因素、行情解读、选购建议 - 资讯快报
  • 如何用智能助手彻底改变B站观看体验:3大突破性功能解析
  • IBM Equal Access Accessibility Checker与主流测试框架集成指南:Jest、Cypress、Karma全解析
  • dbt数据可视化集成:从ETL到BI的完整工作流指南
  • Claude实时流式响应卡顿诊断手册:用eBPF捕获LLM token生成毛刺,定位GPU显存碎片化瓶颈
  • LibVMI高级调试技巧:断点、单步执行与内存转储终极指南
  • OBS Studio画质增强3大核心技术:从算法原理到实战调优
  • LibreCAD:终极免费2D CAD设计软件完全指南
  • 快速掌握faster-whisper:4倍速语音转文字终极指南
  • 终极指南:3步免费解决Windows经典游戏兼容性问题的DirectX修复方案
  • Bitfocus Companion实战攻略:3个关键场景解锁专业流媒体控制面板
  • 2026万国官方保养全攻略|标准化流程、官方收费标准、正规网点筛选、养护核心要点汇总 - 万国官方维修中心
  • Windows设备防火墙终极指南:用HidHide解决游戏外设冲突难题
  • HBM‘s Nuclear Tech Mod安全操作手册:如何避免核事故的10个关键技巧
  • 快速上手HiMarket:10分钟搭建私有AI市场,开启企业AI资源统一管理
  • 2026 年现阶段,札达有实力的管托支吊架直销厂家竞争格局,拆除工程的秘密:这套工具如何让吊装效率翻倍? - 实业推荐官【官方】
  • Quality Prompts在知识图谱构建中的应用:实用案例分享
  • Teable企业级数据协作平台:现代企业数字化转型的架构级解决方案
  • cann/asc-devkit bfloat16高低位交换函数
  • 从mpv内核到macOS原生体验:IINA如何重新定义现代视频播放器
  • 【小程序毕业设计】便民信息发布与检索管理系统的设计与实现 轻量化同城分类信息服务小程序的设计与实现(源码+文档+远程调试,全bao定制等)
  • Pikafish引擎NNUE文件加载失败深度解析与实战解决方案