
一、前言在MySQL性能优化体系里索引是成本最低、收益最高的优化手段几乎90%的慢SQL根源都来自索引设计不合理、索引失效、冗余索引过多三大问题。很多开发建索引只凭直觉WHERE条件字段随手建单列索引、联合索引顺序乱写、不分读写场景疯狂加索引最终出现查询没提速反而INSERT/UPDATE/DELETE写入卡顿、磁盘暴涨。索引本质是空间换时间查询提速的代价是写入时同步维护B树索引页、占用额外磁盘。想要索引效率最大化核心是平衡查询收益与写入损耗本文完整覆盖索引选型标准、联合索引黄金排序、覆盖索引、前缀索引、避坑规范、线上维护方案搭配你之前接口日志表openapi_apilog实战演示。二、前置核心判断哪些字段值得建索引建索引前先算索引选择性区分度这是判断索引价值的第一标准。1. 选择性计算公式-- 数值越接近1索引过滤效果越好SELECTCOUNT(DISTINCTpath)/COUNT(*)ASselectivityFROMopenapi_apilog;选择性0.9优秀优先建索引手机号、订单ID、URL路径、verify_idf_id0.30.9中等适合搭配高区分度字段做联合索引date、user_id0.1极差禁止单独建索引性别、订单状态0/1、是否删除flag2. 必须建索引的字段WHERE查询高频过滤字段user_id、date、path、verify_idf_idJOIN关联条件字段主外键GROUP BY、ORDER BY、DISTINCT高频字段UNIQUE唯一约束字段手机号、账号3. 不建议建索引的场景表数据量1000行全表扫描成本低于索引查找写入极频繁、读极少的表实时流水、临时日志表区分度极低的字段status0/1单独索引无意义超长文本、大TEXT/BLOB字段索引占用空间巨大频繁更新的字段每次修改都会重构索引B树三、索引类型选型选对类型直接提升一倍效率InnoDB主流4类索引不同场景严格区分使用不要混用1. 主键索引 PRIMARY必选性能天花板特性聚簇索引叶子节点存储完整行数据查询无需回表唯一、非空一张表仅1个最优设置使用自增INT/BIGINT做主键自增主键有序写入避免B树页分裂写入性能大幅提升主键长度越小二级索引叶子存储主键越少索引体积更小反面案例用字符串UUID做主键无序插入频繁页分裂读写双慢2. 唯一索引 UNIQUE适用字段业务天然唯一手机号、账号、verify_idf_id优势自带唯一性校验同时查询速度优于普通索引注意允许一条NULL多条NULL不冲突若业务不允许空搭配NOT NULL使用。3. 联合索引复合索引生产最常用一张表多条件查询时一个优质联合索引可以替代多个单列索引大幅减少索引数量、降低写入开销。绝大多数业务查询如日志表WHERE user_id? AND date? AND path LIKE xxx%都应优先设计联合索引而非单列索引叠加。4. 普通索引 INDEX仅用于低频率单条件查询、无唯一性要求的字段作为联合索引补充使用不建议大量创建。选型总结优先主键 → 唯一约束用UNIQUE → 多条件查询用联合索引 → 低频单条件用普通索引四、联合索引黄金设计规则效率核心联合索引是索引优化重中之重顺序写错直接导致索引失效、过滤能力暴跌遵循3条铁律规则1等值条件放最左范围条件放最后底层B树排序逻辑先匹配前一列全部等值再匹配后一列范围查询、、LIKE %xx、BETWEEN后的所有字段无法走索引。业务示例日志表查询条件WHERE user_id1001 AND date2026-07-02 AND path LIKE /openapi/verify_code_identify/?%user_id、date等值匹配path前缀模糊匹配范围类✅ 正确索引顺序idx_user_date_path (user_id, date, path)❌ 错误顺序idx_path_user_date (path, user_id, date)path是范围后面user_id、date完全无法利用索引规则2区分度从高到低排列同等值字段下把选择性高的字段放左侧能快速过滤绝大多数数据减少后续匹配行数。示例user_id区分度远高于date因此user_id排在date前面。规则3排序、分组字段放在索引末尾如果SQL同时带ORDER BY/GROUP BY把排序字段放在联合索引最后避免额外filesort文件排序。-- 查询带creat_time排序SELECT*FROMopenapi_apilogWHEREuser_id?ANDdate?ORDERBYcreat_timeDESC;-- 最优联合索引INDEXidx_user_date_time(user_id,date,creat_time)补充最左前缀原则使用前提联合索引(a,b,c)查询条件必须从最左侧a开始不能跳过首列否则索引无法触发中间列缺失仅能使用左侧匹配字段后续列失效。可用索引where a?、where a? and b?、where a? and b? and c?索引失效where b?、where b? and c?五、覆盖索引极致性能杜绝回表查询原理普通二级索引叶子节点仅存储主键查询非索引字段时需要根据主键回到聚簇索引读取完整数据这个动作叫回表是查询主要性能损耗点。覆盖索引把SELECT需要查询的全部字段放入联合索引MySQL仅遍历索引即可拿到所有数据无需访问原数据表执行计划Extra显示Using index性能提升数倍。实战openapi_apilog日志表原始慢SQL会回表SELECTlogin_ip,price,creat_timeFROMopenapi_apilogWHEREuser_id1001ANDdate2026-07-02ANDpathLIKE/openapi/verify_code_identify/?%;普通联合索引需要回表INDEXidx_user_date_path(user_id,date,path)覆盖索引无回表最优INDEXidx_user_date_path_all(user_id,date,path,login_ip,price,creat_time)使用规范仅高频报表、分页查询使用覆盖索引避免索引字段过多索引体积过大会降低内存缓存命中率禁止SELECT *只查询业务所需字段方便构建覆盖索引。六、字符串字段优化前缀索引减少索引体积长字符串path、url、地址直接全字段建索引会导致索引巨大、缓存失效使用前缀索引截取有效前缀建立索引兼顾区分度与空间。业务示例path固定前缀/openapi/verify_code_identify/?verify_idf_id仅截取前40位即可保证区分度CREATEINDEXidx_path_prefixONopenapi_apilog(path(40));如何计算合适前缀长度逐步测试截取长度保证区分度接近完整字段-- 截取前35位区分度SELECTCOUNT(DISTINCTLEFT(path,35))/COUNT(*)FROMopenapi_apilog;-- 完整字段区分度SELECTCOUNT(DISTINCTpath)/COUNT(*)FROMopenapi_apilog;两者数值接近即可使用该长度做前缀索引。限制前缀索引无法作为覆盖索引只能用于WHERE过滤排序、分组无法使用。七、线上索引避坑这些操作直接让索引报废1. 索引字段包裹函数/表达式前文博客重点-- 失效DATE函数作用于creat_time字段WHEREDATE(creat_time)2026-07-02-- 失效SUBSTR、REPLACE、SUBSTRING_INDEX处理pathWHERESUBSTRING_INDEX(path,verify_idf_id,-1)16优化方案函数只写在常量侧过滤条件使用区间、前缀匹配。2. 后置模糊匹配 %xxx-- 失效全表扫描WHEREpathLIKE%verify_idf_id16-- 生效前缀匹配可走索引WHEREpathLIKE/openapi/verify_code_identify/?verify_idf_id16%3. 隐式类型转换索引字段与查询常量类型不一致MySQL自动转换字段索引失效-- user_id是varchar字符串索引传入数字自动转换字段WHEREuser_id1001-- 正确类型匹配WHEREuser_id10014. 冗余、重复索引已有联合索引(user_id,date)无需单独创建user_id单列索引前者天然支持user_id单条件查询多余索引只会增加写入压力。5. 索引过多单表索引建议不超过5个每条INSERT/UPDATE都要同步更新所有索引写入并发高时会出现锁等待、TPS暴跌。八、分场景索引最佳实践结合日志表openapi_apilog场景1日志报表、读多写少百万级日志表需求按用户、日期、接口路径筛选返回IP、价格、创建时间最优索引覆盖索引ALTERTABLEopenapi_apilogADDINDEXidx_cover_user_date_path(user_id,date,path,login_ip,price,creat_time);优势多条件精准过滤无回表百万数据毫秒返回。场景2仅提取verify_idf_id参数固定接口前缀不要在WHERE中切割path字段改用LIKE前缀匹配WHEREpathLIKE/openapi/verify_code_identify/?verify_idf_id16%配合path前缀索引完全命中索引避免全表扫描。场景3写多读少、实时流水表只保留主键索引1个核心联合索引删除所有低频冗余索引优先保障写入性能。场景4手机号、唯一ID查询直接创建UNIQUE唯一索引查询速度优于普通INDEX同时校验数据唯一性。九、索引后期维护保证长期高效1. 定期清理无用索引查询从未使用的索引批量删除减少写入开销SELECT*FROMsys.schema_unused_indexes;2. 定期优化表碎片大量DELETE/UPDATE会产生索引碎片降低索引扫描效率OPTIMIZETABLEopenapi_apilog;3. 用EXPLAIN验证索引是否生效建完索引必须执行EXPLAIN检查执行计划type列ALL全表扫描差、range/ref正常走索引优key列显示索引名代表命中NULL代表失效Extra出现Using index代表覆盖索引无回表十、全文总结高效索引设置全套流程建前评估计算字段区分度只给高选择性、高频查询字段建索引选型优先自增主键为基础多条件用联合索引唯一字段用UNIQUE联合排序等值放左、范围放右、区分度从高到低排序字段放末尾极致提速高频查询构建覆盖索引长字符串使用前缀索引压缩体积规范SQL禁止索引字段套函数、后置模糊匹配、隐式类型转换控制数量单表索引≤5个杜绝冗余单列索引持续维护定期清理闲置索引、优化碎片上线前EXPLAIN验证。遵循这套规范设计索引可以在不增加服务器硬件的前提下把慢查询耗时从秒级降到毫秒级同时避免索引滥用带来的写入性能衰减。