我在列键上有一个带有text_pattern_ops索引的用户表。问题是密钥列中的数据在其中有需要转义的下划线。有两种方法(我知道)可以转义下划线,只有其中一种方法实际上使用了索引。谁能解释为什么会这样呢?
我已经在下面的查询中粘贴了explain analyze的结果。
查询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
查询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
答案 0 :(得分:2)
你混淆了两个级别。
Posix样式的转义字符串E'foo'
。检查standard_conforming_strings
。
LIKE
operator的模式,其中_
具有可以转义的特殊含义。我引用手册:
匹配文字下划线或百分号而不匹配其他符号 字符,模式中的相应字符必须以 逃避角色。默认转义字符是反斜杠 但是可以使用ESCAPE子句选择不同的一个。至 匹配转义字符本身,写两个转义字符。
索引只能用于左锚定模式。如果模式中间有下划线(_
),则无法使用索引。就像在这个模式表达式中一样:
key like E'999999999_434153_%'
模式中间未转义_
,任何单个字符的通配符 - 可能无法使用text_pattern_ops
的B树索引,尤其是在旧版本中。另请参阅@Richard's comment。
在此模式中,_
被转义,这意味着它代表文字_
而不是单个字符的通配符 - &gt;索引未使用。
key like '999999999\\_434153\\_%'
假设你有standard_conforming_strings = OFF
。使用standard_conforming_strings = ON
,这将导致模式查找文字\
和通配符_
,这可能也不会使用该索引。
您可能对附加模块pg_trgm
感兴趣,该模块允许支持任何 LIKE
表达式的GiST或GIN索引。有关dba.SE here和here