postgres:为什么这个查询不使用数组值的GIN索引?

时间:2017-08-20 02:07:02

标签: postgresql

SQL:

CREATE TEMPORARY TABLE objs (obj_id integer);
CREATE TEMPORARY TABLE sets (obj_id integer[], somecount smallint);

INSERT INTO objs SELECT generate_series(0,10000);
INSERT INTO sets
    SELECT ARRAY[p1.obj_id, p2.obj_id,p3.obj_id], generate_series(0,100)
    FROM objs as p1
    CROSS JOIN objs AS p2
    CROSS JOIN objs AS p3
    WHERE p2.obj_id = p1.obj_id + 1 AND p3.obj_id = p2.obj_id + 1;

CREATE INDEX ON sets USING GIN(obj_id);
SET enable_seqscan = off;
EXPLAIN ANALYZE SELECT * FROM sets WHERE obj_id @> ARRAY[1,2]::integer[];

收率:

                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Seq Scan on sets  (cost=10000000000.00..10000021039.74 rows=25 width=34) (actual time=0.037..333.496 rows=202 loops=1)
   Filter: (obj_id @> '{1,2}'::integer[])
   Rows Removed by Filter: 1009697
 Planning time: 0.727 ms
 Execution time: 333.529 ms
(5 rows)

为什么要进行序列扫描而不使用索引?

更新

在我的服务器上的一个数据库上运行它使用索引上的位图堆扫描(太棒了!)而另一个运行它不会(嘘!)而我不知道为什么。相同的服务器,不同的数据库。

1 个答案:

答案 0 :(得分:1)

postgres扩展程序intarray安装在使用顺序扫描的数据库中,它正在破坏@>运算符。三个选项:

  1. 将调用更改为GIN索引中的OPERATOR(pg_catalog.@>)

  2. 使用gin__int_ops选项创建索引:CREATE INDEX ON sets USING GIN(obj_id gin__int_ops);

  3. 删除intarray扩展名(但我在别处需要,所以不要)