在 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 查询模式、数据分布综合评估索引设计
如需进一步分析某张表的索引效果或执行计划,建议配合 EXPLAIN
、SHOW INDEX
、ANALYZE TABLE
多维度综合判断。