我在玩postgresql9.3的hstore。我正试图像文档状态一样为hstore列使用和索引。我的问题是索引似乎没有被使用。让我给你举个例子:
我创建了一个表"Person":
=# CREATE TABLE Person (Id BIGSERIAL PRIMARY KEY NOT NULL, Values hstore);
并插入一个测试值:
=# INSERT INTO Person (Values, 'a=>1,b=>3');
然后,如果我解释一个SELECT查询,它在'Values'列上使用运算符"@>",我会毫不奇怪地得到:
=# 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)
也许我错过了一些显而易见的东西?
如果您只是在玩它,请确保为索引扫描添加足够的数据。如果只有几行,或者许多行包含类似的值(即where条件的选择性不够),seq扫描通常会比索引扫描更快。
此外,在用测试数据填充表格后,请确保analyze
。
@maxm:的一些额外读数
-
什么是";位图堆扫描";在查询计划中?
-
PostgreSQL查询速度非常慢,限制为1
-
直方图边界中的最大条目数
-
与经典的规范化表相比,postgres JSON索引是否足够高效?
(自编写后者以来,性能已大大提高。)
为什么没有使用他/她的索引?
因为Postgres对整个表(只有一行)进行seq扫描并从单个磁盘页面中筛选出该行的速度比查找索引然后同样对表进行seq搜索以检索该行的数据更快。
询问者如何创建索引是否存在问题?
没有,但请参阅上面关于何时最好使用规范化数据的链接。
并且更喜欢json或jsonb而不是hstore。
是否查询hstore列?要使SELECT查询使用这样的索引,需要修复什么?
没有什么,但请再次查看上面关于何时最好使用规范化数据的链接。
简而言之:当一个表中的页面很少时,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