插入大量新数据不手动ANALYZE,验证InnoDB的统计信息是否自动更新,再发现真正的估算误差根源其实是抽样,不是过期。
很多人以为"没跑ANALYZE TABLE,统计信息就是老的"——这次验证InnoDB是不是真的这么被动。
操作建表插入10万行status='active' EXPLAIN SELECT * FROM t13 WHERE status='active' → 估算 rows=49999 又插入40万行status='banned',中间没有执行任何ANALYZE EXPLAIN SELECT * FROM t13 WHERE status='banned' → 估算 rows=249999
如果统计信息真的是"过期不更新",插入40万行banned之后估算不该有任何反应。
结果SHOW VARIABLES LIKE 'innodb_stats_auto_recalc' → ON 插入40万行banned后,没手动ANALYZE,估算变成了249999 (的banned行数是400000)
原因:innodb_stats_auto_recalc 默认是开着的——InnoDB会在一张表的数据变动累积到一定比例后,自动在后台触发一次统计信息的重新采样,不需要人为手动执行ANALYZE TABLE。插入40万行banned之后,估算数字确实变了(从0变成249999),说明自动重算生效了。
哪怕自动重算了,估算的249999跟的400000还是差了近40%。
结果SHOW VARIABLES LIKE 'innodb_stats_persistent_sample_pages' → 20 执行ANALYZE TABLE t13之后: EXPLAIN SELECT * FROM t13 WHERE status='banned' → 估算 rows=249747(跟没执行ANALYZE前的249999几乎没差) 的banned行数: 400000(COUNT(*)验证)
ANALYZE TABLE 之后,估算数字几乎没变(249999→249747),跟的400000相比,误差还是接近40%。真正的原因不是"统计信息过期没更新",而是InnoDB的持久化统计信息本来就是抽样出来的——默认只采样 innodb_stats_persistent_sample_pages=20 个数据页,用这20个页面的抽样比例去推算整张表的分布。数据分布越倾斜(这张表95%对5%的极端比例),抽样误差就越容易被放大。想让估算更准,能做的是调大采样页数(但会让ANALYZE本身更慢),或者用下一篇会讲的直方图来辅助——单纯"记得跑ANALYZE TABLE"解决不了这个问题,因为它本来就不是"过没过期"的问题。
每一步都是本文上面用EXPLAIN跑出来的原始估算结果。
ANALYZE TABLE / innodb_stats_persistent_sample_pages:验证统计信息的更新与抽样误差