即使未定义 varchar_pattern_ops 且未使用 "C" 区域设置,也使用 LIKE 查询执行 Postgresql 索引扫描
Postgresql Index scan performed with LIKE query even though no varchar_pattern_ops is defined and not using "C" Locale
鉴于以下 table:
CREATE UNLOGGED TABLE table (
col1 VARCHAR(64) NOT NULL,
col2 VARCHAR(255) NOT NULL,
CONSTRAINT table_pk PRIMARY KEY (col1,col2)
);
以及以下 SHOW LC_COLLATE;
结果:
lc_collate
en_US.utf8
以下查询执行索引扫描:
SELECT * FROM table WHERE col1 ='val1' AND col2 LIKE ('prefix%') LIMIT 2;
从它的 EXPLAIN ANALYZE
输出可以看出:
Limit (cost=0.14..8.16 rows=1 width=662) (actual time=0.018..0.022 rows=0 loops=1)
-> Index Only Scan using table_pk on "table" (cost=0.14..8.16 rows=1 width=662) (actual time=0.008..0.012 rows=0 loops=1)
Index Cond: (col1 = 'val1'::text)
Filter: ((col2)::text ~~ 'prefix%'::text)
Heap Fetches: 0
Planning time: 4.562 ms
Execution time: 0.068 ms
问题是包含 LIKE
运算符的查询如何执行索引扫描?
根据 this article as well as this blog 使用 LIKE
运算符但没有“C”语言环境并且没有在索引上设置 varchar_pattern_ops
的情况,应该无法执行索引扫描。
我 运行 在 postgres:9.6
的 docker 图片上
仔细看会发现只有col1
作为“索引条件”,即col2
上的条件不扫描索引。 col2
上的条件在“过滤器”中。
所以一切都如你所愿。这次索引扫描的事件顺序是这样的:
获取具有 col1 = 'val1'
的下一个索引条目
获取该条目的 table 行
检查table行是否可见并满足col2 LIKE 'prefix%'
;如果是,return 那一行
继续扫描步骤 1 中的索引,直到完成
为了帮助您解决潜在问题:如果您可以使用非标准运算符定义主键,那就太好了class,这样主键索引就可以完美地支持您的查询,但那是不可能。这些是您的选择:
删除主键并用 text_pattern_ops
定义唯一索引。如果两列都是 NOT NULL
,那也一样好。
单独在 col2
上创建一个 text_pattern_ops
索引。既可以单独使用,也可以和主键索引结合使用。
在两列上创建第二个索引。
鉴于以下 table:
CREATE UNLOGGED TABLE table (
col1 VARCHAR(64) NOT NULL,
col2 VARCHAR(255) NOT NULL,
CONSTRAINT table_pk PRIMARY KEY (col1,col2)
);
以及以下 SHOW LC_COLLATE;
结果:
lc_collate |
---|
en_US.utf8 |
以下查询执行索引扫描:
SELECT * FROM table WHERE col1 ='val1' AND col2 LIKE ('prefix%') LIMIT 2;
从它的 EXPLAIN ANALYZE
输出可以看出:
Limit (cost=0.14..8.16 rows=1 width=662) (actual time=0.018..0.022 rows=0 loops=1)
-> Index Only Scan using table_pk on "table" (cost=0.14..8.16 rows=1 width=662) (actual time=0.008..0.012 rows=0 loops=1)
Index Cond: (col1 = 'val1'::text)
Filter: ((col2)::text ~~ 'prefix%'::text)
Heap Fetches: 0
Planning time: 4.562 ms
Execution time: 0.068 ms
问题是包含 LIKE
运算符的查询如何执行索引扫描?
根据 this article as well as this blog 使用 LIKE
运算符但没有“C”语言环境并且没有在索引上设置 varchar_pattern_ops
的情况,应该无法执行索引扫描。
我 运行 在 postgres:9.6
仔细看会发现只有col1
作为“索引条件”,即col2
上的条件不扫描索引。 col2
上的条件在“过滤器”中。
所以一切都如你所愿。这次索引扫描的事件顺序是这样的:
获取具有
的下一个索引条目col1 = 'val1'
获取该条目的 table 行
检查table行是否可见并满足
col2 LIKE 'prefix%'
;如果是,return 那一行继续扫描步骤 1 中的索引,直到完成
为了帮助您解决潜在问题:如果您可以使用非标准运算符定义主键,那就太好了class,这样主键索引就可以完美地支持您的查询,但那是不可能。这些是您的选择:
删除主键并用
text_pattern_ops
定义唯一索引。如果两列都是NOT NULL
,那也一样好。单独在
col2
上创建一个text_pattern_ops
索引。既可以单独使用,也可以和主键索引结合使用。在两列上创建第二个索引。