首页/数据/数据库速查/索引基数(cardinality)与统计信息
性能与调优57 条

索引基数(cardinality)与统计信息

cardinality 是索引列唯一值数量估算:越大选择性越好;SHOW INDEX 的 Card 值严重失实会导致优化器选错索引,用 ANALYZE TABLE 刷新。

数据库速查数据更新于 2026-10-13

基数为什么重要

索引基数(cardinality)是索引列上不重复值的估算个数,直接决定选择性:基数越接近表行数,一次索引查找定位到的行越少,优化器就越愿意走这个索引。它是采样估算而非精确值,在数据大比例变更后容易失真,失真时优化器可能选错索引甚至放弃索引,表现为「索引明明存在却全表扫描」。

基本信息

适用平台MySQL 5.7 / 8.0(InnoDB 持久化统计信息)
查看方式SHOW INDEX FROM tbl 的 Cardinality 列
刷新方式ANALYZE TABLE tbl
增强手段8.0 支持 ANALYZE TABLE ... UPDATE HISTOGRAM
相关参数innodb_stats_persistent、innodb_stats_persistent_sample_pages

典型使用场景

  • 新建索引后确认优化器是否采纳,避免出现无效索引
  • 大比例数据变更或不均匀导入后刷新统计信息,稳定执行计划
  • 排查同一 SQL 时而快时而慢:怀疑统计信息漂移导致计划跳变
  • 评估复合索引首列的选择性,判断列序是否合理
  • 为倾斜分布的列建立直方图,改善选择性差的过滤条件

查看与刷新

查看与刷新
-- 查看索引基数与列序
SHOW INDEX FROM appdb.orders\G
-- 大比例变更后刷新统计信息
ANALYZE TABLE appdb.orders;
-- 8.0 为倾斜列建立直方图
ANALYZE TABLE appdb.orders UPDATE HISTOGRAM ON status WITH 64 BUCKETS;
-- 查看已建直方图
SELECT * FROM information_schema.column_statistics WHERE table_name = 'orders';
-- 用执行计划复核索引是否真的被使用
EXPLAIN SELECT * FROM appdb.orders WHERE status = 'paid' AND user_id = 42;

如何判断基数是否可用

观察点正常表现异常表现
Cardinality 与行数比接近 1 表示选择性好远小于行数说明区分度差
与真实去重数对比同数量级差几个数量级说明估算失真
执行计划按预期走目标索引显示全表扫描却又有该索引
列序读数Seq_in_index 与实际查询条件一致首列用不上导致后续列被跳过
统计信息的目标不是精确,而是让优化器做出接近最优的选择;追求精确的代价(每次全量采样)往往高于收益。
不要为了刷新基数频繁对全库执行 ANALYZE TABLE:大表上采样会带来可观 IO,应按热点表按需执行。

易错点

  • Cardinality 与真实值差出几个数量级却无人复核:选错索引的根因常常就在这里
  • 大批量导入后不刷新统计信息:执行计划突然变差,误以为是新代码引入的性能问题
  • 复合索引列序错误:即使基数不低,首列用不上时后续列也无法用于过滤,索引等于白建
  • 给低基数列单独建索引:选择性太差,优化器通常不会采纳,反而增加写入维护成本

数据来源与参考

  • MySQL 8.0 Reference Manual: InnoDB Persistent Statistics
  • MySQL 8.0 Reference Manual: ANALYZE TABLE

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌