postgresql 转义下划线时Postgres索引行为不一致

nxagd54h  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(155)

我有一个用户表,列键上有一个text_pattern_ops索引。问题是键列中的数据包含需要转义的下划线。有两种方法(据我所知)转义下划线,其中只有一种实际使用了索引。有人能解释为什么会这样吗?
我已经粘贴了下面两个查询的解释分析结果。
查询1:

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


查询二:

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

bkhjykvo

bkhjykvo1#

你混淆了两个层次的逃跑。

  1. Posix样式的转义字符串E'foo'。检查standard_conforming_strings的设置。
  2. LIKE运算符的模式,其中_具有可以转义的特殊含义。我引用手册上的话:
    若要匹配文字下划线或百分号而不匹配其他字符,则模式中的相应字符前面必须有转义符。默认转义符是反斜杠,但可以使用ESCAPE子句选择其他转义符。若要与转义符本身匹配,请编写两个转义符。
    索引只能用于左锚定数组。如果模式中间有下划线(_),则无法使用索引。就像是用这种模式表达的:
key like E'999999999_434153_%'

字符串
模式中间的未转义_,任何单个字符的通配符-可能无法将B树索引与text_pattern_ops一起使用,尤其是在旧版本中。另见@理查德评论。
在这个模式中,_被转义,这意味着它代表一个文字_,而不是作为通配符来代表单个字符->不使用索引。

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


假设你有standard_conforming_strings = OFF。对于standard_conforming_strings = ON,这将导致一个查找文字\和通配符_的模式,该模式可能也不使用索引。
您可能会对附加模块pg_trgm感兴趣,该模块允许GiST或GIN索引支持 anyLIKE表达式。请参阅:

相关问题