Karp 的技术博客

MySQL 中,索引是否有效,不仅取决于是否存在索引,还要看这个索引是否具有高区分度(Cardinality,也就是它能否快速筛选出目标数据。

本文将介绍什么是索引区分度、如何查看与分析它,以及在实际工作中如何应用这一概念来优化索引设计。


📌 什么是索引区分度?

索引区分度是指:

索引列中不重复的值的数量表中总记录数 的比例。

✅ 区分度高:

  • 唯一性强
  • 查询效率高
  • MySQL 更倾向于使用该索引

❌ 区分度低:

  • 重复值多(例如 gender, status 等字段)
  • 索引过滤效果差
  • MySQL 可能会选择全表扫描

🔢 公式:

索引区分度(选择性) = COUNT(DISTINCT column) / COUNT(*)

数值越接近 1,表示索引区分度越高,效果越好。


🧪 查看索引区分度

方法一:通过 SHOW INDEX

SHOW INDEX FROM table_name;

重点字段:

字段名含义
Key_name索引名称
Seq_in_index在联合索引中的字段顺序
Column_name字段名
Cardinality估算的不同值的数量(即区分度)
注意:Cardinality 是估算值,可能不准确,可通过 ANALYZE TABLE 进行更新。

方法二:手动计算真实区分度

SELECT COUNT(DISTINCT column_name) / COUNT(*) AS selectivity
FROM table_name;

示例:

SELECT COUNT(DISTINCT email) / COUNT(*) AS selectivity FROM users;

📉 区分度低的索引示例

表结构如下:

CREATE TABLE users (
  id INT PRIMARY KEY,
  gender ENUM('male', 'female'),
  status TINYINT,
  email VARCHAR(255)
);

分析:

字段名预期区分度适合建索引?建议
id高(唯一)✅ 是可作为主键索引
email✅ 是可作为唯一索引
gender低(仅2种)❌ 否单独建索引意义不大
status低(如0/1)❌ 否建议结合其他字段组成联合索引

⚠️ 注意事项

  • MySQL 在选择执行计划时,会根据索引的区分度查询条件统计信息综合判断是否使用索引
  • 区分度太低的字段,即使建了索引,MySQL 查询优化器可能也会放弃使用(执行计划中 type=ALL 表示全表扫描)
  • 如果索引统计信息过旧,可使用以下命令更新:

    ANALYZE TABLE table_name;

🧠 实战优化建议

场景优化建议
高区分度字段可单独建立索引,加快精确查询
中等区分度字段建议和其他字段联合建立索引
低区分度字段(如 status, gender避免单独建索引,必要时可作为联合索引的次要列
联合索引顺序不当优先保证最左字段具有较高区分度

📊 扩展:批量查看索引区分度 SQL 脚本(示例)

SELECT
  TABLE_NAME,
  INDEX_NAME,
  COLUMN_NAME,
  CARDINALITY
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'your_database'
ORDER BY CARDINALITY DESC;
your_database 替换为你的实际数据库名。

✅ 总结

  • 区分度是衡量索引效果的重要指标之一
  • 高区分度的字段更适合建立索引,能显著提高查询性能
  • MySQL 可能会忽略低区分度索引
  • 实际优化时,要结合字段使用频率、SQL 查询模式、数据分布综合评估索引设计

如需进一步分析某张表的索引效果或执行计划,建议配合 EXPLAINSHOW INDEXANALYZE TABLE 多维度综合判断。

mysql

版权属于:karp
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
更新于: 2025年06月07日 02:26
1

目录

来自 《MySQL 索引区分度(Cardinality)详解及优化实践》