执行计划进阶:读懂统计信息与基数估算,理解优化器的“思考方式”

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
PolarDB Agent Flow,2核4GB
PolarDB Agent Express,2核4GB
简介: 执行计划是SQL优化的核心工具,但很多人只关注type和Extra,忽略了执行计划背后的决策依据——统计信息与基数估算。本文从优化器的决策逻辑出发,解释统计信息如何影响基数估算、基数估算如何决定执行计划的选择。通过真实案例展示统计信息过旧如何导致优化器“选错路”,以及如何通过更新统计信息、使用扩展统计等方法来纠正。帮助读者从“看懂执行计划”进阶到“理解优化器为什么这么选”。

大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

上周我们讲了怎么看执行计划——type、key_len、rows、filtered、Extra,每个字段都拆开讲了。但有一个问题一直没回答:优化器是根据什么来决定走哪个执行计划的?

你肯定遇到过这种情况:明明有合适的索引,优化器却选了全表扫描;明明A计划更快,优化器却选了B计划。这时候你可能会骂优化器“笨”,但其实它只是做了一个“基于现有信息的最优判断”——而它依赖的“现有信息”,就是​统计信息​。

如果统计信息不准,优化器的判断就会出错,最终执行计划就会跑偏。

今天我们把执行计划再往深挖一层,讲清楚统计信息和基数估算到底是怎么回事,以及当执行计划“跑偏”时,怎么从统计信息入手把它拉回来。

一、优化器的决策逻辑:它不是“猜”,而是“算”

数据库优化器是基于代价(Cost-Based) 的。它不会凭感觉选执行计划,而是会计算每种可能的执行方式的“代价”,然后选代价最小的那个。

这个“代价”是怎么算出来的?核心公式可以简化为:

代价 ≈ 扫描行数 × 单行处理成本 + 其他开销

其中“扫描行数”就是基数估算(Cardinality Estimation) ——优化器估算的、某个操作会返回的行数。

而基数估算依赖的数据,就是​统计信息​——表有多少行、每列有多少个不同值、数据分布如何。

二、统计信息:优化器的“眼睛”

统计信息是优化器做出决策的依据。如果统计信息不准,优化器的判断就会跟着错。

统计信息主要包括以下几类:

统计信息类型 作用 影响
表级行数 估算全表扫描的基数 决定是否走全表扫描
列级不同值数量(NDV) 估算过滤条件的选择率 决定索引是否被选中
列级NULL值比例 影响条件判断的准确性 影响WHERE条件的估算
数据分布(直方图) 了解列值的分布情况 影响范围查询的估算

举个例子:一张订单表有1000万行,status列有3个不同值(PAID、UNPAID、REFUND)。如果统计信息准确,优化器知道status='PAID'大约占30%,也就是300万行。如果统计信息过旧(比如只统计到表有100万行),优化器会估算status='PAID'只有30万行,从而可能错误地选择索引扫描而非全表扫描——或者反过来。

三、基数估算:优化器的“算力”

有了统计信息,优化器就开始做基数估算——预测每个操作会返回多少行。

基数估算的核心是选择率(Selectivity) 计算。选择率表示某个过滤条件能筛选掉多少数据。

选择率越高,过滤掉的数据越多,返回的行数越少;选择率越低,返回的行数越多。

对于等值条件(WHERE status = 'PAID'),选择率 ≈ 1 / 该列的不同值数量。如果status有3个不同值,选择率约33%。

对于范围条件(WHERE create_time > '2026-01-01'),选择率依赖直方图统计信息来估算数据分布。

如果统计信息不准确,选择率就会算错,基数估算就会偏差,最终执行计划就可能选错。

四、真实案例:统计信息过旧导致的执行计划跑偏

我遇到过这样一个案例:一张日志表有500万行,user_id列上有索引。业务方反馈一条查询突然变慢:

SELECT * FROM user_logs WHERE user_id = 12345 AND create_time > '2026-01-01';

正常情况下,这个查询应该走(user_id, create_time)复合索引,扫描几十行就返回。但实际执行计划显示type=ALL,全表扫描。

查看统计信息后发现,这张表的统计信息还是三个月前收集的——当时表只有50万行。优化器根据旧统计信息估算:user_id = 12345可能返回很多行(因为旧数据中该用户有大量记录),全表扫描可能更“划算”。

执行ANALYZE TABLE user_logs更新统计信息后,优化器重新估算,发现user_id = 12345在500万行中只有几十条记录,复合索引被正确选中,查询从5秒降到了0.05秒。

五、如何检查统计信息是否准确

方法一:对比EXPLAIN的rows与实际行数

执行EXPLAIN后,看rows列的估算值。然后实际执行查询(或使用EXPLAIN ANALYZE),对比实际扫描行数。如果估算值和实际值差了一个数量级以上,统计信息很可能过旧了。

方法二:查看统计信息的最后更新时间

-- MySQL
SELECT table_name, update_time FROM information_schema.tables WHERE table_name = 'your_table';

如果统计信息已经几周甚至几个月没有更新,而表的数据变化很大,就需要执行ANALYZE TABLE

方法三:查看索引的Cardinality

SHOW INDEX FROM your_table;

Cardinality列显示索引列的不同值数量估算。如果Cardinality与实际明显不符,说明统计信息需要更新。

六、如何维护统计信息

1. 定期执行ANALYZE TABLE

对于数据变化频繁的表,建议设置定时任务每天或每周执行ANALYZE TABLE。MySQL 8.0的统计信息虽然是持久化的,但自动更新阈值默认是表数据变化10%,对于核心业务表,这个阈值可能偏大。

2. MySQL 8.0的直方图支持

MySQL 8.0支持为列创建直方图统计信息,对于数据分布不均匀的列特别有用:

ANALYZE TABLE your_table UPDATE HISTOGRAM ON column_name WITH 100 BUCKETS;

3. 关注统计信息的更新时机

建议在以下操作后执行ANALYZE TABLE

  • 批量数据导入后
  • 大量数据删除后
  • 表结构变更后(如添加索引)
  • 定期维护窗口(如每周日凌晨)

七、进阶:当统计信息准确但执行计划仍然跑偏时

有时候统计信息是准确的,但优化器仍然选择了次优计划。这种情况可能的原因包括:

  • 参数设置问题​:某些数据库参数(如eq_range_index_dive_limit)影响优化器的行为
  • 优化器提示(Hint) :在极端情况下,可以使用USE INDEXFORCE INDEX引导优化器

但在使用Hint之前,建议先用EXPLAIN ANALYZE确认真实执行情况,再判断是否需要强制干预。

执行计划是优化器的“决策结果”,统计信息是优化器的“决策依据”,基数估算是优化器的“决策算法”。这三者形成一个完整的决策链条:​统计信息 → 基数估算 → 执行计划​。

如果执行计划看起来不合理,不要急着骂优化器“笨”。先检查统计信息是否准确——大概率是优化器“看错了”,而不是“算错了”。学会从这个角度理解执行计划,你就能从“看懂EXPLAIN”升级到“理解优化器为什么这么选”,在SQL优化上真正做到“知其然也知其所以然”。

小耶在手,SQL 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

相关文章
|
1天前
|
云安全 人工智能 运维
阿里云SecOps Agent,全新安全跨产品执行体验
自然语言驱动 云安全中心/WAF/CFW/ 等多款安全产品联动
1570 1
|
12天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
12天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
855 11
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
|
12天前
|
人工智能 运维 JavaScript
阿里云Qoder CN(原通义灵码)全解析 产品形态、版本划分与技术适配说明
在AI辅助开发与智能办公工具持续普及的当下,阿里云旗下原通义灵码正式更名为Qoder CN,同时延伸出QoderWork CN、Qoder CN CLI、Qoder CN Mobile等多款配套产品,形成覆盖代码开发、日常办公、终端交互、移动端使用的完整工具矩阵。Qoder CN核心定位为AI智能编码助手,深度适配主流代码编辑器、集成开发环境以及终端场景;QoderWork CN则偏向桌面端综合办公辅助,二者面向不同使用场景,划分了多个版本档位,搭配差异化资源配额、功能权限与计费规则,同时兼容多款主流大模型。
888 8
|
1天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
378 2
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
12天前
|
JSON 缓存 安全
通过 CC Switch 本地路由让 Codex CLI 接入 DeepSeek 等第三方模型
CC Switch 通过本地路由(`127.0.0.1:15721`)实现协议转换:将 Codex 的 Responses API 请求自动映射为 DeepSeek 等厂商的 Chat Completions 接口,兼容流式响应与工具调用,无需修改 Codex 源码,安全隔离 API Key。(239字)
2445 7
通过 CC Switch 本地路由让 Codex CLI 接入 DeepSeek 等第三方模型
|
12天前
|
存储 安全 Java
AgentScope Java 2.0:打造分布式、企业级智能体底座
AgentScope 2.0 面向分布式部署、稳定运行、权限安全等企业级需求全面升级,打造支持多租户隔离与长期稳定运行的企业级智能体底座。
|
8天前
|
人工智能 自然语言处理 算法
阿里云百炼Qwen 3.7 Plus与Max实测全解:性价比与多模态能力、成本深度对比
2026年,阿里云百炼平台推出的Qwen 3.7系列成为企业与开发者落地AI应用的核心选择,其中Qwen 3.7 Max与Plus作为两大旗舰版本,定位差异显著:Max是纯文本推理旗舰,专注高强度智能体与复杂逻辑任务;Plus则是多模态全能版,在保留强大文本能力的同时,补齐图像、视频理解能力,且价格大幅降低。本文基于2026年最新实测数据,从核心参数、文本能力、多模态能力、智能体表现、性价比与场景选型六大维度,全面解析两款模型的差异,为用户提供精准选型参考。
438 0