3

我有一个 Postgres 表,其中电话字段存储为varchar(10),但我们经常搜索区号,例如:

select * from bus_t where bus_phone like '555%'

我想创建一个索引来促进这些搜索,但在尝试时出现错误:

CREATE INDEX bus_ph_3 ON bus_t USING btree (bus_phone::varchar(3));

ERROR: 42601: syntax error at or near "::"

我的第一个问题是,我如何做到这一点,但我也想知道对字段的前 X 个字符进行索引是否有意义,或者对整个字段进行索引是否同样有效。

4

2 回答 2

4

like '555%'在完整列上使用索引时,也将被使用。无需仅索引前三个字符。

如果您确实只想索引前 3 个字符(例如为了节省空间),那么您可以使用以下left()功能:

CREATE INDEX bus_ph_3 ON bus_t USING btree (left(bus_phone,3));

但是为了使用该索引,您需要在where子句中使用该表达式:

where left(bus_phone,3) = '555';

但同样:这很可能是矫枉过正,完整列上的索引将足够好,也可以用于其他查询,例如bus_phone = '555-1234'前三个字符上的索引不会。

于 2013-10-08T19:07:08.637 回答
4

实际上,如果您的安装在除 之外的任何其他语言环境(这是典型情况下)运行,则普通 B 树索引通常对于与( ) 或正则表达式 ( )的模式匹配是无用的,即使对于左锚模式也是如此。这是dba.SE 上相关答案中对模式匹配和索引的概述LIKE~~~"C"

varchar_pattern_ops使用运算符类(与您的列匹配)创建索引,varchar并确保阅读手册中有关运算符类的章节

CREATE INDEX bus_ph_pattern_ops_idx ON bus_t (bus_phone varchar_pattern_ops);

您的原始查询可以使用此索引:

... WHERE bus_phone LIKE '555%'

在这种情况下,@a_horse 的答案中描述的前 3 个字符的功能索引的性能几乎相同。

-> SQLfiddle 演示。

通常,对相关前导字符进行功能索引是一个好主意,但您的列只有 10 个字符。考虑到每个元组的开销已经是 28 字节。节省 7 个字节不足以产生重大影响。加上函数调用的成本和通常更快的事实。在 Postgres 9.2 或更高版本中,完整列上的索引也可以用作仅索引扫描中的覆盖索引。xxx_pattern_ops

但是,列中的字符越多,功能索引的好处就越大。如果字符串太长,
您甚至可能不得不求助于前缀索引(或某种其他类型的哈希)。索引有一个最大长度。

如果您决定使用功能索引,请考虑使用该xxx_pattern_ops变体以获得一点额外的性能优势。请务必阅读手册Peter Eisentraut 的博客条目中的优缺点:

CREATE INDEX bus_ph_3 ON bus_t (left(bus_phone, 3) varchar_pattern_ops);

解释错误信息

您必须对功能索引使用标准 SQL 强制转换语法。这会起作用 - 很像带有 的那个left(),但像@a_horse 我更喜欢left()

CREATE INDEX bus_ph_3 ON bus_t USING btree (cast(bus_phone AS varchar(3));
于 2013-10-08T23:36:03.293 回答