LIKE性能取决于模式写法、索引匹配及是否全表扫描:'%keyword'需反向索引,'keyword%'可走B+树但依赖选择性,'%keyword%'应换ES等专用引擎,存储过程中须校验空值防'%%'。

直接说结论:在存储过程中用 LIKE 做模糊搜索,性能好坏不取决于“是不是在存储过程里”,而取决于 LIKE 的模式写法、对应字段是否有合适索引、以及是否触发了全表扫描。
LIKE '%keyword' 后缀匹配为什么慢?怎么加索引才有效
因为标准 B+Tree 索引是按字符串从左到右排序的,LIKE '%keyword' 要求匹配末尾,数据库无法利用索引顺序跳过无关数据,只能扫全表或全索引。
- 不能靠给原字段加普通索引解决(
CREATE INDEX idx_name ON t(name)对name LIKE '%张'无效) - 可行方案是建反向列 + 索引:先
ALTER TABLE t ADD COLUMN name_rev VARCHAR(255) GENERATED ALWAYS AS (REVERSE(name)) STORED,再CREATE INDEX idx_name_rev ON t(name_rev) - 查询时必须同步反向关键词:
SELECT * FROM t WHERE name_rev LIKE REVERSE('张') || '%'(注意不是REVERSE('%张')) - MySQL 5.7 不支持函数索引,必须用生成列;8.0+ 可直接
CREATE INDEX idx_name_rev ON t((REVERSE(name)))
LIKE 'keyword%' 前缀匹配能走索引,但要注意选择性
这是唯一能天然利用 B-Tree 索引的 LIKE 场景,但效果受前缀长度影响极大。
-
name LIKE '张%'走索引快;name LIKE '张%'如果全表 100 万行中有 30 万姓张,索引选择性差,优化器可能仍选全表扫描 - 用
EXPLAIN看type是否为range、key是否显示索引名、rows是否显著小于总行数 - 如果前缀太短(如
'A%'),考虑加过滤条件缩小范围:WHERE status = 'active' AND name LIKE 'A%' - 避免在存储过程中拼接成
CONCAT('%', @kw)或REPLACE类函数——哪怕只用于前缀,也容易让优化器放弃索引
LIKE '%keyword%' 全模糊匹配,别硬扛,换技术栈
单靠 MySQL 原生索引和 LIKE 无法高效支持该场景,强行优化代价高、维护难、效果有限。
- 全文索引(
FULLTEXT)仅对中文支持弱(默认分词粒度大,不支持单字/拼音),且IN NATURAL LANGUAGE MODE不支持通配符,IN BOOLEAN MODE支持*但需开启ft_min_word_len,实际业务中常不准 - 存储过程里嵌套
UNION ALL拆成多个前缀/后缀查询(如name LIKE 'keyword%' OR name LIKE '%keyword' OR name = 'keyword')看似聪明,但执行计划易退化,且结果去重(DISTINCT)成本高 - 真正千万级数据下,应把模糊搜索剥离出事务型数据库:导出到
Elasticsearch或Meilisearch,用倒排索引 + 分词 + 权重排序,响应稳定在 50ms 内 - 若必须留在 MySQL 内,至少把高频模糊字段单独抽成宽表 + 预计算标签(如
name_pinyin、name_initials),用等值或前缀查替代
最容易被忽略的一点:存储过程中变量拼接 LIKE 条件时,如果传入空值或空白字符串,可能意外变成 LIKE '%%',触发全表扫描。务必在 WHERE 前加 IF @kw IS NOT NULL AND TRIM(@kw) != '' 校验——这不是防御性编程,是防止线上慢查询雪崩的实际门槛。










