Inner Join搭配LIKE模糊查询极慢 大表场景求SQL优化方案
问题根因
你当前的查询性能极差的核心原因是写法触发了最坏情况的全表嵌套匹配:100万行句子数据和25万行单词数据做join时,没有任何可走的索引,每一条句子都要和25万个单词逐一做前后模糊匹配,总字符串匹配计算量达到2.5万亿次,且%关键词%格式的LIKE匹配完全无法利用常规B树索引,运行8小时无结果属于预期表现。
另外你原有的LIKE匹配逻辑本身还有准确率问题:CONCAT('% ', words.word ,' %')要求单词前后必须是空格,会漏掉句首单词(前无空格)、句尾单词(后无空格)、单词后接标点的场景,比如句子hello, nice to meet you无法匹配到单词hello。
优化方案
方案1:使用全文索引(改造成本最低,性能提升最显著)
直接给句子表的内容字段建全文倒排索引,利用数据库原生的全文检索能力替代全表模糊匹配,适配你当前的整词匹配需求:
- 先给Sentences表建全文索引:
-- MySQL环境写法,其他数据库语法略有差异,核心都是建全文倒排索引 ALTER TABLE sentences ADD FULLTEXT INDEX ft_sentence_content (sentence);
- 替换原有查询逻辑,用EXISTS+全文匹配替代全表join:
SELECT w.word FROM words w WHERE EXISTS ( SELECT 1 FROM sentences s WHERE MATCH(s.sentence) AGAINST (w.word IN BOOLEAN MODE) )
- 该方案性能优势:全文索引是预构建的倒排索引结构,单词匹配是常量级查找,不需要逐行遍历句子做字符串比对,你当前的数据规模下查询可以在秒级到分钟级返回,同时全文索引的整词匹配默认会忽略标点、句首句尾位置影响,匹配准确率比原LIKE写法更高。
方案2:预构建单词-句子关联表(适合高频查询场景)
如果这类单词匹配查询是业务高频请求,建议提前做数据预处理,避免每次查询都做实时字符串计算:
- 新建中间关联表
sentence_word_map,存储word_id、sentence_id两个关联字段,给两个字段都建普通索引 - 离线跑一次初始化任务:把所有句子按空格、标点拆分为独立单词,和Words表的单词做精确匹配,将存在对应关系的word_id和sentence_id写入中间表
- 后续查询直接关联中间表即可,耗时可以降到毫秒级:
SELECT DISTINCT w.word FROM words w INNER JOIN sentence_word_map m ON w.id = m.word_id
- 该方案注意点:后续句子表有新增、修改操作时,需要同步更新中间表的关联关系,适合查询频率远高于数据写入频率的场景。
不推荐的无效优化
不要尝试给原SQL加各种查询条件、调整join顺序来优化,只要核心逻辑还是逐行做%xxx%的LIKE匹配,性能瓶颈就不会消除,最多只能从8小时降到几小时,达不到可用级别。
内容的提问来源于stack exchange,提问作者Rakan Selawi
相关产品推荐
相关产品推荐

