添加PostgreSQL 9.4 JSON字段索引并仍然使用顺序扫描

时间:2015-07-31 08:49:09

标签: json postgresql

create table testp(id SERIAL, field JSONB);
create index price on testp ((field->>'price'));

insert into testp VALUES(DEFAULT, '{"price": 50, "name": "Smth"}');

explain analyze select field->>'price' from testp;
                                         QUERY PLAN                                             
----------------------------------------------------------------------------------------------------
 Seq Scan on testp  (cost=0.00..25.38 rows=1230 width=32) (actual time=0.011..0.012 rows=1 loops=1)
 Planning time: 0.040 ms
 Execution time: 0.023 ms
(3 rows)

1 个答案:

答案 0 :(得分:2)

仅仅因为索引存在并不意味着它会被使用。查询计划程序尝试最小化查询执行的成本(在EXPLAIN输出中列出)。成本是(大大简化)IO和CPU,IO通常比CPU贵100倍。因此,查询计划程序倾向于对几页行进行顺序扫描,而不是获取保存索引的其他页面。只有当您的表变得非常大时,查询计划程序才会使用任何适当的索引。

如果是您的查询,无论表的大小如何,索引都将从不,因为没有过滤或加入:您只是要求返回所有行

使用大量随机数据加载数据,然后再尝试一些过滤:

INSERT INTO testp(field)
  SELECT json_build_object('price', (random() * 1000)::int, 'name', md5(random()::text))::jsonb
  FROM generate_series(1, 1000000);

但即使有1,000,000行,索引实际上只用于更复杂的查询。

更棘手的问题是您的索引的值为jsonb。只有在将其与另一个jsonb值进行比较时才会使用该索引。如果您的“价格”字段包含integer,则需要一个索引,如:

CREATE INDEX price_int ON testp (CAST(CAST(field->>'price' AS text) AS int));