核心原则:不是不让你做这个功能,是不让你用「导致索引失效的SQL语法」去做 。 所有模糊、匹配、时间筛选、多值查询都有高性能替代方案,下面逐个对应业务场景给出可直接上线的写法。
目录
[一、左模糊/全模糊查询 LIKE '%xxx' / '%xxx%'](#一、左模糊/全模糊查询 LIKE '%xxx' / '%xxx%')
[1. 为什么不推荐?](#1. 为什么不推荐?)
[2. 业务想实现模糊搜索怎么办?(3种正规方案)](#2. 业务想实现模糊搜索怎么办?(3种正规方案))
[二、字段隐式类型转换(字符串=数字 / 数字=字符串)](#二、字段隐式类型转换(字符串=数字 / 数字=字符串))
[1. 为什么失效?](#1. 为什么失效?)
[2. 正确写法(一秒修复)](#2. 正确写法(一秒修复))
三、索引字段用函数/运算:DATE()、+、-、OR、SUBSTR
[1. 典型烂写法(失效)](#1. 典型烂写法(失效))
[2. 问题本质](#2. 问题本质)
[3. 业务替代最优写法(功能一模一样、索引生效)](#3. 业务替代最优写法(功能一模一样、索引生效))
[四、OR 乱使用 + IN 超大集合](#四、OR 乱使用 + IN 超大集合)
[1. OR 失效解决](#1. OR 失效解决)
[2. IN 超大集合解决(in(1,2,3...10000))](#2. IN 超大集合解决(in(1,2,3...10000)))
一、左模糊/全模糊查询 LIKE '%xxx' / '%xxx%'
1. 为什么不推荐?
B+树索引是前缀有序,后缀、全文无顺序,无法走索引,直接全表扫描,大表直接超时。
2. 业务想实现模糊搜索怎么办?(3种正规方案)
方案1:能右模糊就全部用右模糊(优先首选)
需求:搜以"华为"开头的商品 正确写法:LIKE '华为%' → 可以走索引
方案2:必须全模糊/后缀模糊(商品名称、标题搜索)
绝对不要用数据库! 线上标准做法:用 ES / Elasticsearch / Solr 做全文检索,数据库只存原始数据,不扛搜索。
方案3:小表临时兜底
数据量很小(万级以内)可临时用,大表一律上ES。
二、字段隐式类型转换(字符串=数字 / 数字=字符串)
1. 为什么失效?
规则:字段类型被转换,索引失效 例:phone 是字符串索引,你写 where phone=13800001111 MySQL 内部等价于:where CAST(phone AS unsigned)=13800001111 索引字段被函数包裹 → 索引报废。
2. 正确写法(一秒修复)
永远保持两边类型一致
字符串字段 → 加引号:where phone='13800001111'
数字字段 → 不加引号
结论:功能完全不变,但是索引直接生效
三、索引字段用函数/运算:DATE()、+、-、OR、SUBSTR
1. 典型烂写法(失效)
where DATE(create_time) = '2026-05-28'
where user_id + 1 = 1002
2. 问题本质
索引字段被包裹运算 → 无法走B+树有序索引
3. 业务替代最优写法(功能一模一样、索引生效)
时间匹配替代方案(高频)
淘汰:DATE(create_time) = '2026-05-28'
最优:create_time >= '2026-05-28 00:00:00' AND create_time < '2026-05-29 00:00:00'
范围查询替代函数,完美走索引
字段运算替代方案
淘汰:user_id + 1 = 1002
最优:user_id = 1001(把运算丢给参数,不丢给字段)
四、OR 乱使用 + IN 超大集合
1. OR 失效解决
烂写法:where user_id=1001 or status=1(status无索引)
问题:or 只要有一个无索引字段,整句索引失效
替代方案:拆分 UNION ALL
把两个条件拆成两条单查再合并,各自走各自索引,性能翻倍。
2. IN 超大集合解决(in(1,2,3...10000))
问题:IN 数量过大,MySQL优化器放弃索引走全表扫描
业务解决方案:
1)IN 数量控制在 500~1000 以内
2)超大批量匹配 →临时表/关联JOIN查询
3)批量数据优先走缓存、批量SQL,避免超大IN
五、终极口诀
-
字段不动、参数动(永远不对索引字段做函数、运算)
-
能右模糊绝不左模糊,全模糊交给ES
-
类型严格对齐,杜绝隐式转换
-
大IN拆分、烂OR拆分