如何在Postgresql中使用带有hstore列的GIST或GIN索引?

时间:2013-12-14 22:37:31

标签: sql postgresql indexing hstore postgresql-9.3

我正在玩postgresql 9.3的hstore。我正在尝试使用和索引hstore列just like documentation states。我的问题是索引似乎没有被使用。让我举个例子:

我创建了一个表'Person':

=# CREATE TABLE Person (Id BIGSERIAL PRIMARY KEY NOT NULL, Values hstore);

并插入测试值:

=# INSERT INTO Person (Values, 'a=>1,b=>3');

然后,如果我解析使用运算符“@>”的SELECT查询在'价值'栏中,我不出所料地得到:

=# EXPLAIN SELECT P.* FROM Person AS P WHERE P.Values @> hstore('a', '1');
                        QUERY PLAN                        
----------------------------------------------------------
 Seq Scan on person p  (cost=0.00..24.50 rows=1 width=40)
   Filter: ("values" @> '"a"=>"1"'::hstore)

没有索引< - >顺序扫描。说得通。无论如何,如果我创建一个GIN或GIST索引并不重要,解释一直在谈论顺序扫描:

=# CREATE INDEX IX_GIN_VALUES ON Person USING GIN (values);
CREATE INDEX

=# EXPLAIN SELECT P.* FROM Person P WHERE P.values @> hstore('a', '1');

                        QUERY PLAN                        
----------------------------------------------------------
 Seq Scan on person p  (cost=0.00..1.01 rows=1 width=246)
   Filter: ("values" @> '"age"=>"2"'::hstore)

也许我错过了一些明显的东西?

2 个答案:

答案 0 :(得分:6)

如果你只是玩它,一定要为索引扫描添加足够的数据才有意义。如果您只有几行,或者如果许多行包含相似的值(即您的标准不够具有选择性),则seq扫描通常比索引扫描更快。

此外,在填写完测试数据后,请务必analyze


@maxm的额外阅读:

Performance has greatly improved,因为后者是写的。)

  

为什么不使用他/她的索引?

因为Postgres更快地seq扫描整个表(有一行)并从单个磁盘页中过滤掉行,而不是查找索引,然后seq扫描表同样在为了检索行的数据。

  

提问者如何创建索引是否存在问题?

无,但在使用标准化数据时,请参阅上述链接。

并且更喜欢json or jsonb而非hstore。

  

查询hstore列?需要修复什么以便SELECT查询使用这样的索引?

没什么,但是再次看到上面的链接,最好使用标准化数据。

答案 1 :(得分:3)

简而言之:当表中的页面很少时,Postgres的计划程序更喜欢跳过索引,只需加载和扫描行。

CREATE SCHEMA stackoverflow20589058;
--- CREATE SCHEMA

SET search_path TO stackoverflow20589058,"$user",public;
--- SET

CREATE EXTENSION hstore;
--- CREATE EXTENSION

CREATE TABLE Person (Id BIGSERIAL PRIMARY KEY NOT NULL, Values hstore);
--- CREATE TABLE

WITH Vals(n) AS (SELECT * FROM generate_series(1,10))
INSERT INTO Person (
  SELECT n AS Id, hstore('a=>'||n||', b=>'||n) AS Values FROM Vals
);
--- INSERT 0 10

EXPLAIN SELECT P.* FROM Person AS P WHERE P.Values @> hstore('a', '1');
---                         QUERY PLAN                        
--- ----------------------------------------------------------
---  Seq Scan on person p  (cost=0.00..24.50 rows=1 width=40)
---    Filter: ("values" @> '"a"=>"1"'::hstore)
--- (2 rows)

CREATE INDEX IX_GIN_VALUES ON Person USING GIN (values);
--- CREATE INDEX

------------------------- When there are few values, a sequential scan is
------------------------- often the best search strategy. Grabbing a few
------------------------- pages in sequence can be cheaper than making an
------------------------- extra disk seek to load the index.
EXPLAIN SELECT P.* FROM Person AS P WHERE P.Values @> hstore('a', '1');
---                        QUERY PLAN                        
--- ---------------------------------------------------------
---  Seq Scan on person p  (cost=0.00..1.12 rows=1 width=40)
---    Filter: ("values" @> '"a"=>"1"'::hstore)
--- (2 rows)

TRUNCATE Person;
--- TRUNCATE TABLE

WITH Vals(n) AS (SELECT * FROM generate_series(1,100000))
INSERT INTO Person (
  SELECT n AS Id, hstore('a=>'||n||', b=>'||n) AS Values FROM Vals
);
--- INSERT 0 100000

------------------------- When there are many rows, using the index can
------------------------- allow us to skip quite a lot of I/O; so
------------------------- Postgres's planner makes use of the index.
EXPLAIN SELECT P.* FROM Person AS P WHERE P.Values @> hstore('a', '1');
---                                    QUERY PLAN                                   
--- --------------------------------------------------------------------------------
---  Bitmap Heap Scan on person p  (cost=916.83..1224.56 rows=107 width=40)
---    Recheck Cond: ("values" @> '"a"=>"1"'::hstore)
---    ->  Bitmap Index Scan on ix_gin_values  (cost=0.00..916.80 rows=107 width=0)
---          Index Cond: ("values" @> '"a"=>"1"'::hstore)
--- (4 rows)

DROP SCHEMA stackoverflow20589058 CASCADE;
--- NOTICE:  drop cascades to 2 other objects
--- DETAIL:  drop cascades to extension hstore
--- drop cascades to table person
--- DROP SCHEMA