为什么PostgreSQL在某些排序规则下不使用我的索引进行文本前缀搜索?

时间:2013-03-24 10:57:55

标签: postgresql indexing prefix postgresql-9.2 postgresql-performance

考虑:

create table tab (foo text not null);
create index tab_ix_foo on tab(foo);

select * from tab where foo like 'pre%';

Postgres不使用索引进行搜索。使用排序规则"POSIX"时,Postgres使用索引:http://sqlfiddle.com/#!12/ed1cc/1

使用排序规则"en_US"时,Postgres使用顺序扫描:http://sqlfiddle.com/#!12/efb18/1

为什么会有差异?

1 个答案:

答案 0 :(得分:4)

使用C以外的区域设置(即POSIX)时,您需要使用LIKE opclass为~text_pattern_ops前缀文本搜索创建索引。请参阅Operator classesindex types上的文档。我确信这个文档比该文档页面更好,但我现在似乎无法找到它。

如果我改变您的SQLFiddle以使用text_pattern_ops en_US索引you'll see that it's able to use the index

create index tab_ix_foo on tab using btree (foo collate "en_US" text_pattern_ops);
--                                                              ^^^^^^^^^^^^^^^^

如果您在9.2+中使用COLLATE选项,则很可能需要为不同的排序规则创建不同的索引,因为根据定义,不同的排序规则意味着不同的顺序排列字符串,因此不同的b树组织。您似乎已在测试中执行此操作。

您的数据可能太小而无法使用索引特别有用。尝试使用更有用的数据进行测试。

This post可能很有用,Collation support上的文档也可能有用。


为什么你不能为不同的排序规则使用相同的b-tree索引,请考虑b-trees需要稳定一致的排序,但是:

regress=> SELECT ' Bill''s' > ('bills' COLLATE "POSIX");
 ?column? 
----------
 f
(1 row)

regress=> SELECT ' Bill''s' > ('bills' COLLATE "en_US");
 ?column? 
----------
 t
(1 row)

如您所见,排序规则会更改排序顺序。根据定义,这就是整理所做的事情。尝试对不同的排序规则使用相同的索引就像尝试对不同的功能使用相同的功能索引一样;这绝对没有意义。