跳转到主内容
极星编程网:以代码为星,赴技术山海!

mysql如何查看索引区分度_mysql cardinality基数分析

Cardinality是MySQL对索引列不同值个数的采样估算,不精确;应通过ANALYZE TABLE更新统计,并用COUNT(DISTINCT col)/COUNT(*)计算真实区分度,低于0.03慎用索引,高区分度字段须置联合索引最左位。 怎么看
SHOW INDEX
里的
Cardinality
值靠不靠谱
Cardinality
是 MySQL 对索引列“不同值个数”的估算值,不是精确统计。它来自采样(默认约 1/16 的页),所以大表或数据分布突变后容易严重失真——比如明明有 100 万个用户 ID,
Cardinality
却显示只有 12 万。 查之前先
ANALYZE TABLE your_table
,强制更新统计信息(尤其在大批量 INSERT/DELETE 后) 对比
SHOW INDEX
的
Cardinality
和实际
COUNT(DISTINCT column)
,差 3 倍以上就别信它
Cardinality
为
NULL
或
1
通常意味着索引失效、字段全 NULL 或采样失败,得人工验证 用 SQL 精确算区分度:别只看
Cardinality
,要自己算比值 区分度 =
COUNT(DISTINCT column)
/
COUNT(*)
,这个比值才是决定索引是否值得建的关键数字。0.001(千分之一)和 0.95(95%)带来的查询性能差异是数量级的。 直接跑这句:
SELECT COUNT(DISTINCT user_id) / COUNT(*) AS selectivity FROM users;
如果字段是联合索引的一部分(如
(del_flag, unit_id, user_id)
),必须按顺序拼接计算:
SELECT COUNT(DISTINCT CONCAT(del_flag, '-', unit_id, '-', user_id)) / COUNT(*) FROM your_table;
区分度 0.8(80%)才建议放联合索引最左位 为什么
del_flag
这种字段绝不能放联合索引最左边 像
del_flag
这类状态位字段,区分度往往低于 0.01(比如 99% 是 0,1% 是 1),放最左会导致整个联合索引几乎无法跳过扫描——优化器大概率放弃走索引,改用全表扫描。 MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 正确顺序应把高区分度字段放左:比如
(user_id, unit_id, del_flag)
,而不是反过来 如果必须过滤
del_flag = 0
,优先考虑分区表或物理归档,而非依赖索引剪枝
WHERE del_flag = 0 AND user_id = ?
能走索引,但
WHERE user_id = ? AND del_flag = 0
才稳定;顺序错一格,执行计划可能完全不同 Python 脚本批量查多个字段的区分度(避免手动重复) 线上表几十个字段,一个个写 SQL 太累。用脚本自动拉出所有索引列 + 实时区分度,比翻
SHOW INDEX
直观得多。 核心逻辑就是循环查
COUNT(DISTINCT col)
和
COUNT(*)
,再算比值 注意避开
TEXT
/
BLOB
字段(
COUNT(DISTINCT)
会报错),加
try/except
捕获 示例片段:
cursor.execute("SELECT COUNT(*) FROM users")
total = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(DISTINCT email) FROM users")
distinct = cursor.fetchone()[0]
print(f"email selectivity: {distinct/total:.4f}")
真实环境里,
Cardinality
只是个快照提示,不是判决书。区分度算出来不到 0.03,再漂亮的执行计划也救不了索引;而一个
user_id
区分度 0.999 却被塞在联合索引第三位,等于白建。

相关文章