调大 innodb_stats_persistent_sample_pages 能改善 rows 估算,因为默认仅采样20页易受数据倾斜影响,增大采样页数可提升基数与选择性估算准确性;需配合 ANALYZE TABLE 生效,并注意函数、索引使用等导致统计失效的场景。

为什么调大 innodb_stats_persistent_sample_pages 能改善 rows 估算?
因为 rows 不是算出来的,而是基于采样页中键值分布“猜”出来的。默认只采样 20 个页(innodb_stats_persistent_sample_pages=20),样本太少时,碰到数据倾斜(比如 95% 的订单 status='done')、长尾分布或大表(>1000 万行),估算就容易严重偏离。调高这个值,相当于让优化器“多看几页”,基数(CARDINALITY)和选择性估算更稳,rows 自然更接近实际扫描量。
innodb_stats_persistent_sample_pages 设多少才合适?
没有全局最优值,得看表规模和写入压力:
- 千万行以下、分布较均匀的表:保持默认
20即可 - 1000 万–5 亿行,且有范围查询或低基数字段(如 status、type):建议设为
100~200 - 超大表(>5 亿行)或数据高度倾斜:可临时设到
400,但必须在业务低峰期操作 - MySQL 8.0+ 且已建直方图的列:优先用
CREATE STATISTICS,不必盲目拉高该参数
调了参数但 rows 还不准?这些动作缺一不可
改参数只是铺路,不触发重采样等于白调:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 必须执行
ANALYZE TABLE your_table_name,否则旧统计仍生效 - 确认
innodb_stats_persistent = ON(MySQL 5.6+ 默认开启),否则采样结果不落盘,重启即丢 - 检查是否被长事务阻塞:长时间未提交的事务会锁住统计信息更新,
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 300可查 - 避免在主库高峰期执行:
ANALYZE TABLE期间会对索引加意向锁,可能拖慢写入
容易被忽略的失效场景
即使采样很准,rows 仍可能失真,因为优化器根本“没机会用上”统计:
-
WHERE条件含函数,如YEAR(create_time) = 2024:索引失效,优化器退化为全表估算 - 联合索引只用非最左前缀列,如索引是
(a,b,c)但查WHERE b = 1:该路径无对应统计 - 分区表跨多个分区查询:优化器叠加各分区估算值,而非探测实际匹配分区
-
EXPLAIN的rows是单次访问估算,嵌套循环连接下会被反复乘积放大,不是最终结果集大小
真正关键的不是让 rows 多准,而是理解它在哪种条件下失效——比如看到 rows=1 但实际扫了 50 万行,大概率是函数导致统计绕过,而不是采样页数不够。










