如何优化含多LIKE的SQL查询?求简洁有效的替代语句
搞定SQL模糊匹配的简洁写法&性能优化
先说说为啥你用IN没结果?
兄弟,你踩了个常见的坑:IN ('%error%','%fail%')是精确匹配啊!它只会找LogText完全等于'%error%'或者'%fail%'的记录,而不是包含这些字符串的——这和你原本用LIKE '%error%' OR LIKE '%fail%'的逻辑根本不是一回事,当然查不到结果啦。
给你几个更简洁的有效写法
根据你的需求,整理了几种替代多个LIKE的方案,按需选:
1. 规整版的多LIKE写法(可读性拉满)
虽然你不想用多个LIKE,但其实稍微整理下,可读性也很强,而且逻辑和原语句完全一致:
SELECT * FROM BatchServices.dbo.TaskLog WHERE TaskGroup LIKE '%CSR%' -- 注意你后来改成了`= 'csr'`,如果数据库大小写敏感的话会不匹配,建议和原语句保持一致 AND EntryTime BETWEEN '20190407' AND '20190408' AND (LogText LIKE '%error%' OR LogText LIKE '%fail%') ORDER BY EntryTime ASC;
要是你的SQL Server是2016及以上版本,还能用STRING_SPLIT来简化,以后加关键词只改字符串就行:
SELECT * FROM BatchServices.dbo.TaskLog t WHERE TaskGroup LIKE '%CSR%' AND EntryTime BETWEEN '20190407' AND '20190408' AND EXISTS ( SELECT 1 FROM STRING_SPLIT('error,fail', ',') s WHERE t.LogText LIKE CONCAT('%', s.value, '%') ) ORDER BY EntryTime ASC;
2. 用PATINDEX替代LIKE
PATINDEX支持通配符,只要返回值大于0就说明包含目标字符串,和LIKE逻辑完全等价,写法也差不多:
SELECT * FROM BatchServices.dbo.TaskLog WHERE TaskGroup LIKE '%CSR%' AND EntryTime BETWEEN '20190407' AND '20190408' AND (PATINDEX('%error%', LogText) > 0 OR PATINDEX('%fail%', LogText) > 0) ORDER BY EntryTime ASC;
如果以后要搞更复杂的模糊匹配(比如带正则的),PATINDEX会比LIKE更灵活。
这类模糊查询的优化技巧
模糊匹配(尤其是%xxx这种前缀通配的)最头疼的就是索引失效,给你几个实用的优化方向:
- 尽量避免前缀通配符:如果业务允许,把
'%error%'改成'error%',这样就能用上LogText字段的非聚集索引了。要是必须前后都模糊,试试全文索引——在LogText上创建全文索引后,用CONTAINS查询,性能提升特别明显:SELECT * FROM BatchServices.dbo.TaskLog WHERE TaskGroup LIKE '%CSR%' AND EntryTime BETWEEN '20190407' AND '20190408' AND CONTAINS(LogText, 'error OR fail') ORDER BY EntryTime ASC; - 先筛选再模糊:你的原语句已经做得很好了——先通过EntryTime和TaskGroup过滤掉大部分无关数据,再对剩下的LogText做模糊匹配,这样能大幅减少需要处理的数据量。
- 注意大小写问题:你后来把
TaskGroup LIKE '%CSR%'改成了taskgroup = 'csr',如果你的数据库排序规则是大小写敏感的,这会漏掉TaskGroup是大写CSR的记录,建议要么保持LIKE,要么确认表的collation设置。 - 创建覆盖索引:如果经常跑这类查询,建个覆盖索引,包含EntryTime、TaskGroup和LogText,这样查询不用回表,速度会快很多:
CREATE NONCLUSTERED INDEX IX_TaskLog_EntryTime_TaskGroup_LogText ON BatchServices.dbo.TaskLog (EntryTime, TaskGroup) INCLUDE (LogText);
内容的提问来源于stack exchange,提问作者shary.sharath
相关产品推荐
相关产品推荐

