在全表的子集上操作时LIKE查询的性能影响

lat*_*lip 4 sql postgresql indexing pattern-matching sql-like

我很欣赏LIKE查询很慢,因为它们无法编入索引.但是,我很好奇在这种情况下的性能影响:

说我有一个像这样的表:

user_id  |  message 
-------------------
   1     |  foo bar baz
   1     |  bar buz qux
   .     .      .
   .     .      .
   2     |  bux bar foo
   2     |  bar
Run Code Online (Sandbox Code Playgroud)

我说100万行,但有10,000个用户,所以每个用户有大约100条消息.

显然搜索如下:

SELECT * FROM table WHERE message like '%ar%';
Run Code Online (Sandbox Code Playgroud)

会很慢.但是在我的应用程序中,我只会搜索用户的消息:

SELECT * FROM table WHERE message like '%ar%' AND user_id = 2;
Run Code Online (Sandbox Code Playgroud)

其中user_id列将被索引.

我是否正确地认为在这样的场景中,Postgres只会在使用索引的user_id列而不是完整的表后对用户~100行执行慢LIKE查询 - 从而限制了我的性能损失?

而且只要任何一个用户只有大约100条消息,这样的查询对于10或1亿用户来说不会明显变慢?

Erw*_*ter 8

@MatBailie已经清除了你的主要问题.我想解决你的断言:

我很欣赏LIKE查询很慢,因为它们无法编入索引.

这不完全正确.

首先,这已经很久了,左锚定模式 可以使用索引.这适用于正则表达式(~)以及LIKE(~~)和SIMILAR TO.我最近在dba.SE上写了一篇关于此事的综合评论:

这可能对您不起作用,因为问题中的模式没有锚定.如果是这样,您可以使用多列索引获得优化性能,该索引使用列的 文本模式运算符类text_pattern_ops,message如下所示:

CREATE INDEX tbl_user_id_message_idx ON tbl (user_id, message text_pattern_ops);
Run Code Online (Sandbox Code Playgroud)

对于以下查询:

SELECT *
FROM   tbl
WHERE  user_id = 2
AND    message ~~ 'bar%'; -- left anchored LIKE
Run Code Online (Sandbox Code Playgroud)

其次,从PostgreSQL 9.1开始,你可以使用pg_trgm扩展并用它创建一个GIST或GIN索引,所有模式都可以使用.一些限制适用.维护这样的索引更加昂贵,因此对于只读或很少编写的表最有用.细节:

Depesz有一个相关的教程.