在WHERE中使用SUBSTRING()、CONCAT()或REPLACE()会导致索引失效,引发全表扫描;正确做法是用前缀索引+LIKE替代SUBSTRING(),用生成列+索引替代CONCAT(),ETL预处理替代运行时REPLACE()。

别在WHERE里用SUBSTRING()、CONCAT()或REPLACE()做条件过滤——它们会让索引彻底失效,查询从毫秒变秒级甚至更长。
为什么SUBSTRING()和LIKE不能混用
常见错误是写WHERE SUBSTRING(url, 1, 5) = 'https'来匹配协议头。这会强制全表扫描,因为函数阻断了索引下推。即使你对url建了普通索引,MySQL也无法跳过计算直接定位。
- 正确做法是建前缀索引:
ALTER TABLE logs ADD INDEX (url(5)),再改写为WHERE url LIKE 'https%' - 如果字段长度波动大(比如有的URL极长),前缀索引长度要覆盖绝大多数真实值,可用
SELECT MAX(LENGTH(SUBSTRING_INDEX(url, '/', 3))) FROM logs辅助估算 -
SUBSTRING()本身开销不小,尤其配合LENGTH()嵌套时;若只需判断开头,LEFT(url, 5)通常更快且语义更清晰
CONCAT()导致索引失效的隐蔽场景
不只是WHERE CONCAT(a, b) = 'xxx'这种明显写法。更常见的是在JOIN条件或ORDER BY里用CONCAT(),比如JOIN users ON CONCAT(u.first_name, u.last_name) = t.full_name——这会让两个表都失去索引优势,变成嵌套循环+逐行拼接。
- 真正解法不是优化函数,而是避免实时拼接:加生成列
ALTER TABLE users ADD full_name VARCHAR(100) AS (CONCAT(first_name, last_name)) STORED,再对full_name建索引 - 如果业务允许,写入时就预计算并存入冗余字段,比每次查都拼接省CPU得多
- 注意
CONCAT()遇到NULL会返回NULL,而CONCAT_WS()会跳过NULL,选哪个取决于你的空值语义是否可接受
高频REPLACE()和TRIM()怎么不拖慢查询
这两个函数常用于清洗数据,但放在WHERE或SELECT里批量执行时,CPU占用会陡增。尤其REPLACE()在长文本上反复替换,性能曲线几乎是线性恶化。
- 能提前处理就别 runtime 处理:ETL阶段统一清洗,或触发器中自动标准化(如入库时
SET clean_phone = REPLACE(REPLACE(phone, '-', ''), ' ', '')) - 如果必须查时处理,优先用
TRIM()而非REPLACE()去空格——TRIM()是原生C实现,REPLACE()需正则引擎介入,开销高一个数量级 - 对大小写统一需求,别用
LOWER(username) = 'admin',而应在写入时就存小写值,并确保查询也用小写字面量
最易被忽略的一点:函数本身快慢只是表象,真正卡住的是它让优化器“看不见”索引。哪怕UPPER()再快,只要出现在WHERE左侧,就等于告诉MySQL:“别用索引,老老实实扫表吧”。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xinjizixun/21066.html