2

我有一个用户表,列键上有一个 text_pattern_ops 索引。问题是键列中的数据有下划线,需要转义。有两种方法(我知道)来转义下划线,并且只有在其中一种中实际使用了索引。谁能解释为什么会这样?

我已经为以下两个查询粘贴了解释分析的结果。

查询一:

EXPLAIN ANALYZE
select distinct userid from user
where userstatus IN ('Active')
and ( key like E'999999999_434153_%' or parentid = 434153) ;

查询计划:

HashAggregate  (cost=340685.17..340687.84 rows=267 width=4) (actual time=22678.760..22678.760 rows=0 loops=1)
  ->  Seq Scan on user  (cost=0.00..340684.50 rows=267 width=4) (actual time=22678.754..22678.754 rows=0 loops=1)
        Filter: (((userstatus)::text = 'Active'::text) AND (((key)::text ~~ '999999999_434153_%'::text) OR (parentid = 434153)))
Total runtime: 22678.879 ms

查询 2:

EXPLAIN ANALYZE
select distinct userid from user
where userstatus IN ('Active')
and ( key like '999999999\\_434153\\_%' or parentid = 434153) ;

产生警告:

WARNING:  nonstandard use of \\ in a string literal
LINE 1: ...userstatus IN ('Active') and ( key like '999999999...
                                                             ^
HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.

查询计划:

HashAggregate  (cost=344.50..347.17 rows=267 width=4) (actual time=226.127..226.127 rows=0 loops=1)
  ->  Bitmap Heap Scan on user  (cost=11.09..343.83 rows=267 width=4) (actual time=226.123..226.123 rows=0 loops=1)
        Recheck Cond: (((key)::text ~~ '999999999\\_434153\\_%'::text) OR (parentid = 434153))
        Filter: (((userstatus)::text = 'Active'::text) AND (((key)::text ~~ '999999999\\_434153\\_%'::text) OR (parentid = 434153)))
        ->  BitmapOr  (cost=11.09..11.09 rows=84 width=0) (actual time=226.121..226.121 rows=0 loops=1)
              ->  Bitmap Index Scan on user_key_idx  (cost=0.00..5.44 rows=1 width=0) (actual time=145.758..145.758 rows=0 loops=1)
                    Index Cond: (((key)::text ~>=~ '999999999_434153_'::text) AND ((key)::text ~<~ '999999999_434153`'::text))
              ->  Bitmap Index Scan on user_parentid_key1  (cost=0.00..5.52 rows=84 width=0) (actual time=80.358..80.358 rows=0 loops=1)
                    Index Cond: (parentid = 434153)
Total runtime: 226.256 ms
4

1 回答 1

2

您混淆了两个级别的转义。

  1. Posix 风格的转义字符串E'foo'。检查您的设置standard_conforming_strings

  2. LIKE运算符的模式,其中_具有可以转义的特殊含义。我引用手册:

    要匹配文字下划线或百分号而不匹配其他字符,pattern 中的相应字符必须以转义字符开头。默认转义字符是反斜杠,但可以使用 ESCAPE 子句选择不同的转义字符。要匹配转义字符本身,请编写两个转义字符。

该索引只能用于左锚定模式。如果_模式中间有下划线 ( ),则不能使用索引。就像在这个模式表达式中一样:

key like E'999999999_434153_%'

在模式中间未转义_,任何单个字符的通配符 - 可能无法将 B-tree 索引与 一起使用text_pattern_ops,尤其是在旧版本中。另请参阅@Richard 的评论

在这种模式中,_转义了,这意味着它代表文字_,而不是单个字符的通配符-> 未使用的索引。

key like '999999999\\_434153\\_%'

假设你有standard_conforming_strings = OFF. standard_conforming_strings = ON这样会导致模式寻找可能不使用索引的文字\和通配符。_

您可能对附加模块感兴趣pg_trgm,它允许支持任何 LIKE表达式的 GiST 或 GIN 索引。在此处此处的 dba.SE 相关答案中了解更多信息

于 2012-12-10T10:30:17.717 回答