如何使用多个LIKE运算符并让查询有效利用索引?
如何在PostgreSQL中高效查询匹配多个LIKE条件的行(利用索引)
嘿,关于用多个LIKE条件查数据还得蹭上索引这件事,我刚好有实战经验——你说的三种写法里,确实只有一种能让PostgreSQL乖乖用上咱们建的索引。咱们一步步来聊:
先搭好测试环境
首先得把表和索引建好,这里的关键是TEXT_pattern_ops索引,它是PostgreSQL里让TEXT类型的前缀LIKE查询能用上索引的核心:
CREATE TABLE dir ( id BIGSERIAL PRIMARY KEY, path TEXT NOT NULL ); -- 这个索引是前缀LIKE能走索引的前提 CREATE INDEX path_idx ON dir(path TEXT_pattern_ops);
1. 唯一能利用索引的写法:OR连接多个前缀LIKE
直接用OR把每个LIKE '前缀%'的条件连起来,PostgreSQL的查询优化器能精准识别这种模式,直接命中咱们建的索引:
EXPLAIN ANALYZE SELECT id, path FROM dir WHERE path LIKE 'A%' OR path LIKE 'B%' OR path LIKE 'C%';
跑一下EXPLAIN ANALYZE你就能看到,计划里明确用到了path_idx索引,数据量大的时候性能提升特别明显——因为索引直接帮咱们过滤掉了大部分不符合前缀的行,不用全表扫描。
2. 踩坑写法1:用LIKE ANY(ARRAY[])
很多人为了简化代码会这么写:
EXPLAIN ANALYZE SELECT id, path FROM dir WHERE path LIKE ANY(ARRAY['A%', 'B%', 'C%']);
看起来清爽,但可惜的是,PostgreSQL目前的优化器还没法把这种写法转换成能利用前缀索引的执行计划,只能走全表扫描,数据多的时候卡到怀疑人生。
3. 踩坑写法2:正则表达式前缀匹配
还有人会用正则来实现类似逻辑,比如:
EXPLAIN ANALYZE SELECT id, path FROM dir WHERE path ~ '^[ABC]';
逻辑上和之前的OR写法完全一致,但优化器不会把这种正则前缀匹配和TEXT_pattern_ops索引关联起来,同样只能全表扫,性能拉胯。
最后划重点
- 只有多个OR连接的前缀LIKE条件(
LIKE 'X%')能触发TEXT_pattern_ops索引的使用 - 后缀匹配(
'%X')或全模糊匹配('%X%')不管用哪种写法都没法用索引,这种场景要么接受全表扫,要么考虑用全文检索之类的其他方案 - 别图省事用
LIKE ANY或者正则前缀,这些都没法蹭到索引的红利
内容的提问来源于stack exchange,提问作者Michał Albrycht




