PostgreSQL LIKE查询性能变化

Jas*_*son 103 postgresql indexing query-optimization pattern-matching sql-like

关于LIKE查询数据库中特定表的响应时间,我看到了相当大的变化.有时我会在200-400毫秒内得到结果(非常可接受),但有时候返回结果可能需要30秒.

我知道LIKE查询是非常耗费资源的,但我只是不明白为什么响应时间会有这么大的差异.我已经在该owner1字段上构建了一个btree索引,但我认为这对LIKE查询没有帮助.有人有主意吗?

示例SQL:

SELECT gid, owner1 FORM parcels
WHERE owner1 ILIKE '%someones name%' LIMIT 10
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%') LIMIT 10
Run Code Online (Sandbox Code Playgroud)

和:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('someones name%') LIMIT 10
Run Code Online (Sandbox Code Playgroud)

有类似的结果.
表行数:约95,000.

Erw*_*ter 263

FTS不支持 LIKE

以前接受的答案是不正确的.全文搜索及其全文索引根本不适用于LIKE运算符,它有自己的运算符,不适用于任意字符串.它运行在的话基于字典和制止.它确实支持单词的前缀匹配,但不支持LIKE运算符:

Trigram索引 LIKE

安装附加模块pg_trgm,该模块为GIN和GiST三元组索引提供运算符类,以支持所有LIKEILIKE模式,而不仅仅是左锚定模式:

示例索引:

CREATE INDEX tbl_col_gin_trgm_idx  ON tbl USING gin  (col gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)

要么:

CREATE INDEX tbl_col_gist_trgm_idx ON tbl USING gist (col gist_trgm_ops);
Run Code Online (Sandbox Code Playgroud)

示例查询:

SELECT * FROM tbl WHERE col LIKE '%foo%';   -- leading wildcard
SELECT * FROM tbl WHERE col ILIKE '%foo%';  -- works case insensitively as well
Run Code Online (Sandbox Code Playgroud)

卦?短弦怎么样?

文字少于3个字母的索引值仍然有效.手册:

在确定字符串中包含的三元组时,每个单词被认为有两个空格前缀,一个空格后缀.

搜索模式少于3个字母?手册:

对于两者LIKE和正则表达式搜索,请记住,没有可提取三元组的模式将退化为全索引扫描.

意思是,索引/位图索引扫描仍然有效(预备语句的查询计划不会中断),它只是不会给你带来更好的性能.通常没有大的损失,因为单字母或双字母字符串几乎没有选择性(超过基础表匹配的几个百分点)并且索引支持不会提高性能,因为全表扫描更快.


text_pattern_ops 用于前缀匹配

对于左锚定模式(没有前导通配符),您可以使用适合btree索引的运算符类获得最佳值:text_pattern_opsvarchar_pattern_ops.标准Postgres的内置功能,无需额外的模块.性能相似,但指数要小得多.

示例索引:

CREATE INDEX tbl_col_text_pattern_ops_idx ON tbl(col text_pattern_ops);
Run Code Online (Sandbox Code Playgroud)

示例查询:

SELECT * FROM tbl WHERE col LIKE 'foo%';  -- no leading wildcard
Run Code Online (Sandbox Code Playgroud)

或者,如果您应该使用'C'语言环境(实际上没有语言环境)运行数据库,那么无论如何都会根据字节顺序对所有内容进行排序,并使用默认运算符类的普通btree索引来完成工作.

dba.SE上这些相关答案的更多细节,解释,示例和链接:


Ant*_*sma 7

可能快速的是具有区分大小写的锚定模式,可以使用索引.即在匹配字符串的开头没有通配符,因此执行程序可以使用索引范围扫描.(文档中的相关注释在这里)除非您专门为此目的创建索引(参见功能索引),否则下层和ilike也将失去使用索引的能力.

如果要在字段中间搜索字符串,则应查看全文或三字母索引.其中第一个是Postgres核心,另一个是contrib模块.


Ste*_*uan 6

我最近遇到了类似的问题,一个包含 200000 条记录的表,我需要重复执行 LIKE 查询。就我而言,正在搜索的字符串是固定的。其他领域各不相同。因此,我能够重写:

SELECT owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%');
Run Code Online (Sandbox Code Playgroud)

作为

CREATE INDEX ix_parcels ON parcels(position(lower('someones name') in lower(owner1)));

SELECT owner1 FROM parcels
WHERE position(lower('someones name') in lower(owner1)) > 0;
Run Code Online (Sandbox Code Playgroud)

当查询快速返回并验证索引正在使用时,我很高兴EXPLAIN ANALYZE

 Bitmap Heap Scan on parcels  (cost=7.66..25.59 rows=453 width=32) (actual time=0.006..0.006 rows=0 loops=1)
   Recheck Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
   ->  Bitmap Index Scan on ix_parcels  (cost=0.00..7.55 rows=453 width=0) (actual time=0.004..0.004 rows=0 loops=1)
         Index Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
 Planning time: 0.075 ms
 Execution time: 0.025 ms
Run Code Online (Sandbox Code Playgroud)