作者
digoal
日期
2020-09-28
标签
PostgreSQL , jsonb , 矩阵
背景
矩阵数据, 全矩阵所有行搜索.
```
create table b (id int, c1 jsonb);
insert into b values (1, '[{"a":1,"b":2},{"c":2,"d":4}]');
create index idx_b_1 on b using gin (c1);
postgres=> set enable_seqscan=off;
SET
postgres=> explain select * from b where c1 @> '{"c":2}' ;
QUERY PLAN
Bitmap Heap Scan on b (cost=3.30..4.41 rows=1 width=36)
Recheck Cond: (c1 @> '{"c": 2}'::jsonb)
-> Bitmap Index Scan on idx_b_1 (cost=0.00..3.30 rows=1 width=0)
Index Cond: (c1 @> '{"c": 2}'::jsonb)
(4 rows)
```
矩阵数据, 根据指定矩阵行搜索.
例如搜索第2行, 无法直接使用jsonb索引. (与array类型从1开始编号不同, json的array从0开始编号)
```
postgres=> explain select * from b where c1 -> 1 ->> 'b'='2';
QUERY PLAN
Seq Scan on b (cost=10000000000.00..10000000001.02 rows=1 width=36)
Filter: (((c1 -> 1) ->> 'b'::text) = '2'::text)
(2 rows)
```
优化方法
由于gin索引是基于KEY的单颗树, 所以没有办法直接指定矩阵哪行来搜索。 需要使用partial index:
优化方法1、(PS:当然, 我们可以不顾哪行先搜索, 然后再recheck的方式来完成这个需求, 但是引入了额外的filter。)
``` select * from b where c1 @> '{"b" :1}' and c1->1->>'b' = '1';
postgres=> explain select * from b where c1 @> '{"b" :1}' and c1->1->>'b' = '1'; QUERY PLAN
Bitmap Heap Scan on b (cost=3.30..4.42 rows=1 width=36) Recheck Cond: (c1 @> '{"b": 1}'::jsonb) Filter: (((c1 -> 1) ->> 'b'::text) = '1'::text) -> Bitmap Index Scan on idx_b_1 (cost=0.00..3.30 rows=1 width=0) Index Cond: (c1 @> '{"b": 1}'::jsonb) (5 rows) ```
优化方法2、partial index方法的优化要求: 矩阵的行数有限, 太多了的话partial index会太多.
```
-- 每行创建一个partial index
postgres=> create index idx_b_2 on b using gin (((c1->1)::jsonb));
CREATE INDEX
postgres=> create index idx_b_3 on b using gin (((c1->2)::jsonb));
CREATE INDEX
postgres=> explain select * from b where (c1 -> 1)::jsonb @> '{"b":1}';
QUERY PLAN
Bitmap Heap Scan on b (cost=3.30..4.42 rows=1 width=36)
Recheck Cond: ((c1 -> 1) @> '{"b": 1}'::jsonb)
-> Bitmap Index Scan on idx_b_2 (cost=0.00..3.30 rows=1 width=0)
Index Cond: ((c1 -> 1) @> '{"b": 1}'::jsonb)
(4 rows)
```
参考
《PostgreSQL 用条件索引(部分索引, partial index), 旁路某些索引的使用, 例如sort》
《PostgreSQL 店铺运营实践 - JSON[]数组 内部标签数据等值、范围检索100倍+加速示例 (含,单值+多值列合成)》
《PostgreSQL 优化case - where A字段范围 order by B字段排序 limit x》
PostgreSQL 许愿链接
您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.
9.9元购买3个月阿里云RDS PostgreSQL实例
PostgreSQL 解决方案集合
德哥 / digoal's github - 公益是一辈子的事.





