PostgreSQL:多列索引jsonb,整数部分与 @> 和 = 条件一起使用 设置我做了什么预期结果实际结果结论

问题描述

设置

一个包含一个 jsonbattributes一个非唯一数字 ID campaignid 的表:

  CREATE TABLE coupons (
    id integer NOT NULL,created timestamp with time zone DEFAULT Now( ) NOT NULL,campaignid bigint NOT NULL,attributes jsonb NOT NULL
  );

该表将有多达 5 亿行、attributes 中的任意键/值和数百个不同的 campaignid 值。

表上存在两个索引:

CREATE INDEX campaignid_attrs_idx ON coupons
USING gin (campaignid,attributes);

CREATE INDEX campaignid_idx ON coupons
USING btree (campaignid,deleted);

我做了什么

我执行了查询

SELECT COUNT(*)
FROM coupons
WHERE 
(campaignid = 97 AND
   attributes @> '{"CountryId": 3}');

预期结果

我希望 campaignid_attrs_idx 上的索引 (campaignid,attributes) 被完全使用并且查询完成得相当快。

实际结果

执行查询需要很长时间(约 40 秒)。

这是 explain (ANALYZE,COSTS)输出

Aggregate  (cost=32337.78..32337.79 rows=1 width=8) (actual time=39726.410..39726.414 rows=1 loops=1)
  ->  Bitmap Heap Scan on coupons  (cost=30164.40..32332.44 rows=2136 width=0) (actual time=16893.439..39549.891 rows=1088478 loops=1)
"        Recheck Cond: ((attributes @> '{""CountryId"": 3}'::jsonb) AND (campaignid = 97))"
        Rows Removed by Index Recheck: 10531586
        Heap Blocks: exact=138344 lossy=583282
        ->  BitmapAnd  (cost=30164.40..30164.40 rows=2136 width=0) (actual time=16837.885..16837.887 rows=0 loops=1)
              ->  Bitmap Index Scan on coupons_campaignid_attrs_index  (cost=0.00..1465.15 rows=178954 width=0) (actual time=9872.279..9872.279 rows=81799565 loops=1)
"                    Index Cond: (attributes @> '{""CountryId"": 3}'::jsonb)"
              ->  Bitmap Index Scan on campaignid_idx  (cost=0.00..28697.93 rows=2135515 width=0) (actual time=6454.972..6454.972 rows=3088167 loops=1)
                    Index Cond: (campaignid = 97)
Planning Time: 0.175 ms
Execution Time: 39726.480 ms

结论

似乎索引 campaignid_attrs_idx 用于查询 attributes @> '{"CountryId": 3}' 的第一部分,返回约 80M 行,而索引 campaignid_idx 用于 {{ 1}} 子句 WHERE 并行返回 ~3M 行。将两个部分的结果相交以获得满足这两个条件的集合。然后是位图堆扫描,验证结果集符合所需的条件,花费了大部分时间 (16893.439..39549.891)


我的主要问题是,为什么不使用 campaignid = 97 来过滤这两个条件?



EDIT:我删除了第二个索引 campaignid_attrs_idx 以查看多列索引是否将用于这两种情况。奇怪的是我仍然看到索引扫描中使用的唯一条件之一。这是计划:

campaignid_attrs_idx

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...