news 2026/5/7 17:57:34

MySQL 联合索引创建效果评估

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 联合索引创建效果评估

一、为什么需要评估未创建索引的 Cardinality?

在数据库优化中,Cardinality(基数)是决定是否创建索引、以及如何排列联合索引列顺序的核心指标。它表示索引列中不重复值的数量。

核心矛盾:索引尚未创建时,数据库不会为其维护统计信息。我们无法直接SHOW INDEX查看 Cardinality,必须手动估算或模拟

关键认知:联合索引的 Cardinality ≠ 单列 Cardinality 的简单叠加,而是取决于列之间的组合唯一性。


二、方法一:手动计算(最准确)

2.1 基础计算查询

-- 假设你想测试 (col1, col2) 的联合索引 Cardinality-- 计算唯一组合数SELECTCOUNT(*)AStotal_rows,COUNT(DISTINCTcol1)AScol1_cardinality,COUNT(DISTINCTcol2)AScol2_cardinality,COUNT(DISTINCTCONCAT(col1,'-',col2))AScombined_cardinalityFROMyour_table;

2.2 示例输出解读

+------------+------------------+------------------+-------------------+ | total_rows | col1_cardinality | col2_cardinality | combined_cardinality| +------------+------------------+------------------+-------------------+ | 1000000 | 50000 | 100 | 800000| +------------+------------------+------------------+-------------------+

分析逻辑

指标数值含义
total_rows1,000,000表总行数
col1_cardinality50,000col1 单独的不重复值数
col2_cardinality100col2 单独的不重复值数
combined_cardinality800,000两列组合的不重复值数

判断标准

  • combined_cardinality(80万)越接近total_rows(100万),联合索引效果越好
  • 如果combined_cardinalitycol1_cardinality(5万),说明 col2 几乎没有额外区分度,不建议将 col2 加入联合索引

三、方法二:计算选择性(Selectivity)

选择性是 Cardinality 的"标准化"指标,消除了表大小差异的影响,更适合跨表比较。

3.1 选择性计算公式

-- 联合索引选择性 = 唯一组合数 / 总行数-- 越接近 1 越好SELECTCOUNT(DISTINCTCONCAT(col1,'-',col2))/COUNT(*)ASselectivity,CASEWHENCOUNT(DISTINCTCONCAT(col1,'-',col2))/COUNT(*)>0.1THEN'适合建索引'WHENCOUNT(DISTINCTCONCAT(col1,'-',col2))/COUNT(*)>0.01THEN'效果一般'ELSE'不建议建索引'ENDASsuggestionFROMyour_table;

3.2 选择性决策矩阵

选择性范围建议说明
> 0.1 (10%)强烈推荐建联合索引区分度极高,索引收益明显
0.01 ~ 0.1 (1%~10%)效果一般根据查询频率和写操作比例决定
< 0.01 (1%)不建议建索引区分度太低,索引维护成本高,考虑其他优化方案

四、方法三:对比不同列顺序

联合索引的列顺序直接影响查询性能。最左前缀原则要求:将 Cardinality 高的列放在前面。

4.1 列顺序对比查询

-- 测试 (a,b) vs (b,a) 哪个更好SELECT'a_first'ASorder_type,COUNT(DISTINCTCONCAT(a,'-',b))AScardinalityFROMyour_tableUNIONALLSELECT'b_first'ASorder_type,COUNT(DISTINCTCONCAT(b,'-',a))AScardinalityFROMyour_table;

4.2 列顺序决策原则

┌─────────────────────────────────────────────────────────┐ │ 原则:将 Cardinality 高的列放在联合索引的左侧(前面) │ │ │ │ 原因: │ │ 1. 最左前缀原则要求查询必须从索引最左列开始匹配 │ │ 2. 高 Cardinality 列在前,能更快缩小扫描范围 │ │ 3. 避免索引"失效"——跳过最左列后,后续列无法使用索引 │ └─────────────────────────────────────────────────────────┘

示例场景

  • 订单表:user_id(10万 Cardinality)+status(5 Cardinality)
  • 推荐索引:(user_id, status)—— 先按用户过滤,再按状态过滤
  • 不推荐:(status, user_id)—— 先按状态(只有5种)过滤,效率极低

五、方法四:使用 EXPLAIN 模拟(MySQL 8.0)

虽然无法直接查看未创建索引的 Cardinality,但可以通过创建临时索引模拟查询效果。

5.1 临时索引测试流程

-- Step 1: 创建临时索引(仅用于测试,数据量大时慎用)ALTERTABLEyour_tableADDINDEXidx_test(col1,col2);-- Step 2: 查看优化器是否选择该索引EXPLAINSELECT*FROMyour_tableWHEREcol1='xxx'ANDcol2='yyy';-- Step 3: 查看实际 CardinalitySHOWINDEXFROMyour_tableWHEREKey_name='idx_test';-- Step 4: 测试完成后立即删除(避免影响线上性能)ALTERTABLEyour_tableDROPINDEXidx_test;

5.2 注意事项

生产环境慎用ALTER TABLE会锁表,大表操作可能导致长时间阻塞。建议在:

  • 低峰期执行
  • 或先在测试环境(相同数据量)验证
  • 或使用 MySQL 8.0 的INSTANT ADD COLUMN(部分场景支持在线DDL)

六、方法五:快速估算(大表优化)

对于千万级甚至亿级大表,COUNT(DISTINCT)全表扫描非常慢,可以采用采样估算策略。

6.1 随机采样估算

-- 随机采样 10000 条估算整体 CardinalitySELECTCOUNT(DISTINCTCONCAT(col1,'-',col2))*(SELECTCOUNT(*)FROMyour_table)/10000ASestimated_cardinality,COUNT(DISTINCTCONCAT(col1,'-',col2))*(SELECTCOUNT(*)FROMyour_table)/10000/(SELECTCOUNT(*)FROMyour_table)ASestimated_selectivityFROM(SELECTcol1,col2FROMyour_tableORDERBYRAND()LIMIT10000)ASsample;

6.2 采样策略优化

表大小采样行数误差范围执行时间预估
< 100万全表计算0%< 5秒
100万 ~ 1000万10,000±5%2-10秒
1000万 ~ 1亿50,000±3%10-30秒
> 1亿100,000±2%30-60秒

提示ORDER BY RAND()在超大表上也很慢,可以改用主键范围采样

-- 更高效的采样方式(基于主键范围)SELECTcol1,col2FROMyour_tableWHEREidBETWEENFLOOR(RAND()*(SELECTMAX(id)FROMyour_table))ANDFLOOR(RAND()*(SELECTMAX(id)FROMyour_table))+10000LIMIT10000;

七、综合评估报告模板

7.1 多组候选联合索引对比

-- 综合评估报告:分析多组候选联合索引SELECT'idx_a_b'ASindex_name,COUNT(DISTINCTCONCAT(a,'-',b))AScardinality,COUNT(DISTINCTCONCAT(a,'-',b))/COUNT(*)ASselectivity,COUNT(DISTINCTa)ASfirst_col_card,COUNT(DISTINCTb)ASsecond_col_cardFROMyour_tableUNIONALLSELECT'idx_b_a'ASindex_name,COUNT(DISTINCTCONCAT(b,'-',a))AScardinality,COUNT(DISTINCTCONCAT(b,'-',a))/COUNT(*)ASselectivity,COUNT(DISTINCTb)ASfirst_col_card,COUNT(DISTINCTa)ASsecond_col_cardFROMyour_tableUNIONALLSELECT'idx_a_c'ASindex_name,COUNT(DISTINCTCONCAT(a,'-',c))AScardinality,COUNT(DISTINCTCONCAT(a,'-',c))/COUNT(*)ASselectivity,COUNT(DISTINCTa)ASfirst_col_card,COUNT(DISTINCTc)ASsecond_col_cardFROMyour_table;

7.2 输出示例与解读

+-----------+------------+------------+----------------+-----------------+ | index_name| cardinality| selectivity| first_col_card | second_col_card | +-----------+------------+------------+----------------+-----------------+ | idx_a_b | 850000 | 0.8500 | 100000 | 200 | | idx_b_a | 850000 | 0.8500 | 200 | 100000 | | idx_a_c | 120000 | 0.1200 | 100000 | 5000 | +-----------+------------+------------+----------------+-----------------+

决策分析

候选索引选择性推荐列顺序结论
idx_a_b0.85a在前优秀,高选择性
idx_b_a0.85b在前选择性相同,但b的 Cardinality 低,不适合放前面
idx_a_c0.12a在前中等,根据查询频率决定

最终推荐:创建INDEX idx_a_b (a, b),因为:

  1. 选择性高达 0.85,远超 0.1 阈值
  2. a的 Cardinality(10万)远高于b(200),符合"高 Cardinality 列在前"原则

八、已创建索引的 Cardinality 查看

如果你已经创建了索引,可以直接查看数据库维护的统计信息:

-- 查看表的索引统计信息SHOWINDEXFROMyour_table;-- 或查询 information_schemaSELECTTABLE_NAME,INDEX_NAME,COLUMN_NAME,CARDINALITY,ROUND(CARDINALITY/TABLE_ROWS,4)ASselectivityFROMinformation_schema.STATISTICSsJOINinformation_schema.TABLEStONs.TABLE_SCHEMA=t.TABLE_SCHEMAANDs.TABLE_NAME=t.TABLE_NAMEWHEREs.TABLE_NAME='your_table';

注意information_schema.STATISTICS中的CARDINALITY估算值,基于采样统计,可能与实际值有偏差。对于关键决策,建议用本文的方法重新计算。


九、决策流程图

开始评估联合索引 Cardinality │ ▼ ┌─────────────────────┐ │ 表数据量 < 100万? │ └─────────────────────┘ │ │ 是 否 │ │ ▼ ▼ 全表 COUNT(DISTINCT) 采样估算(10,000~100,000条) │ │ └──────┬───────┘ ▼ ┌─────────────────────────────┐ │ 计算 combined_cardinality │ │ 和 selectivity │ └─────────────────────────────┘ │ ▼ ┌─────────────────────────────┐ │ selectivity > 0.1 ? │ └─────────────────────────────┘ │ │ 是 否 │ │ ▼ ▼ ┌──────────┐ ┌─────────────────────────┐ │ 强烈推荐 │ │ selectivity > 0.01 ? │ │ 建索引 │ └─────────────────────────┘ └──────────┘ │ │ 是 否 │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ 效果一般 │ │ 不建议 │ │ 根据查询 │ │ 建索引 │ │ 频率决定 │ │ │ └──────────┘ └──────────┘

十、核心结论与公式

未创建的联合索引没有现成的 Cardinality 统计,但你可以通过COUNT(DISTINCT CONCAT(col1, '-', col2))来计算唯一组合数,这就是联合索引的实际 Cardinality。

核心公式

联合索引 Cardinality = COUNT(DISTINCT CONCAT(col1, '-', col2, '-', ...)) 联合索引选择性 = 联合索引 Cardinality / 表总行数

黄金法则

法则说明
值越大越好Cardinality 越接近总行数,索引效果越好
高列在前联合索引中,Cardinality 高的列放在左侧
选择性 > 0.1强烈推荐建索引
选择性 < 0.01维护成本高于收益,不建议建索引

十一、快速参考卡片

-- 一键评估联合索引 (col1, col2)SELECTCOUNT(*)AStotal_rows,COUNT(DISTINCTcol1)AScol1_card,COUNT(DISTINCTcol2)AScol2_card,COUNT(DISTINCTCONCAT(col1,'-',col2))AScombined_card,ROUND(COUNT(DISTINCTCONCAT(col1,'-',col2))/COUNT(*),4)ASselectivity,CASEWHENCOUNT(DISTINCTCONCAT(col1,'-',col2))/COUNT(*)>0.1THEN'强烈推荐'WHENCOUNT(DISTINCTCONCAT(col1,'-',col2))/COUNT(*)>0.01THEN'效果一般'ELSE'不建议'ENDASsuggestionFROMyour_table;

记住:Cardinality 评估是索引优化的"地基",地基不稳,后续的 EXPLAIN 分析、SQL 改写都是空中楼阁。在创建任何联合索引前,先用本文的方法算一算,避免盲目建索引带来的性能反噬。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/7 17:49:28

CopaWeb:轻量级全栈Web开发框架,一体化架构提升开发效率

1. 项目概述&#xff1a;一个面向开发者的轻量级Web应用构建框架最近在和一些独立开发者朋友交流时&#xff0c;发现大家普遍面临一个痛点&#xff1a;想快速搭建一个功能完整、界面现代的Web应用&#xff0c;但又不希望被Vue、React这类大型前端框架的复杂生态和构建流程所束缚…

作者头像 李华
网站建设 2026/5/7 17:47:29

Windows个性化革命:用Windhawk打造独一无二的系统体验

Windows个性化革命&#xff1a;用Windhawk打造独一无二的系统体验 【免费下载链接】windhawk The customization marketplace for Windows programs: https://windhawk.net/ 项目地址: https://gitcode.com/gh_mirrors/wi/windhawk 厌倦了千篇一律的Windows界面&#xf…

作者头像 李华
网站建设 2026/5/7 17:45:34

构建AI Agent排行榜:从数据摄取到实时排名的架构实践

1. 项目概述&#xff1a;一个为AI Agent量身定制的排行榜如果你和我一样&#xff0c;深度使用过Claude Desktop或者OpenClaw这类AI桌面应用&#xff0c;你可能会发现一个痛点&#xff1a;我们每天都在和不同的AI助手&#xff08;Agent&#xff09;互动&#xff0c;但究竟哪个Ag…

作者头像 李华
网站建设 2026/5/7 17:44:16

魔兽地图格式转换技术架构解析:w3x2lni全栈解决方案

魔兽地图格式转换技术架构解析&#xff1a;w3x2lni全栈解决方案 【免费下载链接】w3x2lni 魔兽地图格式转换工具 项目地址: https://gitcode.com/gh_mirrors/w3/w3x2lni 对于魔兽争霸III地图开发者而言&#xff0c;版本兼容性和地图格式管理是长期存在的技术痛点。w3x2l…

作者头像 李华
网站建设 2026/5/7 17:44:08

《龙虾OpenClaw系列:从嵌入式裸机到芯片级系统深度实战60课》016、电源管理单元——低功耗模式与唤醒策略

OpenClaw系列016&#xff1a;电源管理单元——低功耗模式与唤醒策略 一、一个让我熬夜三天的bug 去年做一款电池供电的工业传感器节点&#xff0c;MCU选型时拍脑袋选了某款Cortex-M4&#xff0c;号称有7种低功耗模式。结果产品原型出来&#xff0c;实测待机电流比规格书多了整整…

作者头像 李华