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