我正在玩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)
也许我错过了一些明显的东西?
答案 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