因为mysql b+树索引仅支持左前缀匹配(如'abc%'),而'%关键词%'触发全表扫描;fulltext对中文分词弱、更新延迟高且不支持通配前缀;真正实现10–50ms需用es实时检索或mysql 8.0+函数索引处理结构化json。

为什么LIKE和普通索引撑不住毫秒级搜索
MySQL默认的B+树索引对LIKE '%关键词%'完全无效,全表扫描一上来就卡在几百毫秒甚至秒级。即使加了fulltext索引,中文分词支持弱、更新延迟高,且MATCH ... AGAINST不支持模糊前缀(比如“张*”或“*伟”)。真实业务里查用户昵称、商品标题、日志内容时,只要带通配符或需高亮片段,原生方案基本掉链子。
真正能压到10–50ms响应的,只有两条路:一是把查询压力卸给专用搜索引擎,二是用MySQL 8.0+的JSON字段+函数索引做轻量级加速——但后者只适合结构清晰、关键词固定的场景。
用Elasticsearch替代MySQL做实时检索
这不是“上ES就完事”,而是要明确边界:MySQL管事务和关联,ES管搜。常见踩坑点包括同步延迟、数据一致性、DSL写错导致慢查询。
- 同步不能靠定时dump:用
binlog解析(如canal或debezium)实时推到ES,延迟可压到200ms内
- ES里
text字段必须配"analyzer": "ik_max_word"(中文),否则搜“笔记本”匹配不到“笔记本电脑”
- 避免
wildcard查询,改用match_phrase_prefix或completion建议器,前者响应快、支持高亮,后者适合搜索框联想
- MySQL主键必须作为
id写进ES文档,否则回查时连不上原记录
POST /product/_search
{
"query": {
"match_phrase_prefix": {
"title": { "query": "无线耳机", "max_expansions": 50 }
}
},
"highlight": {
"fields": { "title": {} }
}
}
MySQL 8.0+用函数索引加速JSON字段搜索
如果你的数据本身就在MySQL里、改架构成本高,且搜索字段是结构化JSON(比如tags数组、specs对象),可以用GENERATED COLUMN + FUNCTIONAL INDEX硬刚。
binlog解析(如canal或debezium)实时推到ES,延迟可压到200ms内text字段必须配"analyzer": "ik_max_word"(中文),否则搜“笔记本”匹配不到“笔记本电脑”wildcard查询,改用match_phrase_prefix或completion建议器,前者响应快、支持高亮,后者适合搜索框联想id写进ES文档,否则回查时连不上原记录tags数组、specs对象),可以用GENERATED COLUMN + FUNCTIONAL INDEX硬刚。
例如用户表有个profile JSON字段,存着{"interests": ["编程", "摄影"]},想快速查“所有兴趣含‘编程’的用户”:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 先加生成列:
ALTER TABLE users ADD interest_list TEXT AS (JSON_EXTRACT(profile, '$.interests')) STORED; - 再建函数索引:
CREATE INDEX idx_interests ON users ((CAST(interest_list AS CHAR(255)))); - 查的时候用
WHERE interest_list LIKE '%编程%'——注意:必须走生成列,直接JSON_CONTAINS(profile, '"编程"', '$.interests')不走索引
性能取决于JSON扁平程度。嵌套三层以上的数组或对象,JSON_EXTRACT开销会明显上升,响应可能回到100ms以上。
别忽略查询缓存与连接池的实际影响
哪怕ES或函数索引把单次查询干到20ms,如果应用层没配好,照样拖成300ms。
- PHP/Python等客户端默认没开连接复用,每次请求新建MySQL连接,光握手+认证就占50–100ms;必须启用
connection pool并设最小空闲连接数
- ES客户端若没配
sniffer或集群节点列表写死,某节点挂了就超时;建议用elasticsearch-py的RetryOnTimeout + max_retries=2
- HTTP层别用
curl发ES请求——它不复用TCP连接,短连接开销大;改用requests.Session()或官方HTTP client
实际压测时,经常发现90%的“慢搜索”根本不是引擎问题,而是连接没复用、JSON字段没预处理、ES mapping写错导致分词失败——这些地方比选什么技术栈更值得先盯紧。
connection pool并设最小空闲连接数sniffer或集群节点列表写死,某节点挂了就超时;建议用elasticsearch-py的RetryOnTimeout + max_retries=2
curl发ES请求——它不复用TCP连接,短连接开销大;改用requests.Session()或官方HTTP client










