Postgres - 大型jsonb柱的性能

时间:2017-02-02 04:50:15

标签: json performance postgresql indexing jsonb

我们在其中一个数据库表中使用Postgres jsonb类型。表结构如下所示:

CREATE TABLE T (
  id UUID NOT NULL PRIMARY KEY,
  payload JSONB
);

CREATE INDEX ON T USING gin (payload jsonb_path_ops);

Payload是一个复杂的json字符串。以下是一个例子:

{
    "business": {
        "taxId": "626642071",
        "legalName": "Jon's Deli",
        "phoneNumbers": [
            {
                "phoneType": "Business",
                "telephoneNumber": "8384407555"
            },
            {
                "phoneType": "Work",
                "telephoneNumber": "6032255248"
            }
        ],
        "addresses": [
            {
                "city": "San Francisco",
                "state": "CA",
                "postalCode": "94101",
                "countryCode": "USA",
                "addressLine1": "123 Market St"
            }
        ]
    },
    "stakeholders": [
        {
            "person": {
                "taxId": "540646815",
                "firstName": "GdXFouh",
                "lastName": "IlUAcgCGz",
                "dateOfBirth": "1980-12-11",
                "emailAddress": "jywxsijgix@qaqmlz.com",
                "phoneNumbers": [
                    {
                        "phoneType": "Mobile",
                        "telephoneNumber": "4901371573"
                    }
                ],
                "addresses": [
                    {
                        "city": "San Francisco",
                        "state": "CA",
                        "postalCode": "94101",
                        "countryCode": "USA",
                        "addressLine1": "123 Market St"
                    }
                ]
            }
        }
    ]
}

请注意,phoneNumbersaddressesstakeholders是数组,这意味着数组中可以有多个元素。

我尝试在表格中插入一百万行。 payload的每个字段都是随机生成。最初,测试程序运行得非常快。但是在插入大约800,000行之后,它每1000行被卡住 - 插入1000行,然后测试程序挂起2分钟,然后它返回并插入另外1000行,......

我们怀疑这是由大量的jsonb索引更新引起的。因为在单个索引中有许多要更新的字段。我们只想确认是否有人遇到过同样的问题。

实际上,我们不需要为整个payload列编制索引。只需要某些字段:business->taxIdbusiness->phoneNumbers-> telephoneNumberstakeholders->person->taxIdstakeholders->person->emailAddress

我尝试过以下两个指数:

CREATE INDEX ON T USING gin ((payload->'business'->'taxId') jsonb_path_ops);
CREATE INDEX ON T USING gin ((payload ->'stakeholders'->'person'->'taxId') jsonb_path_ops);

并运行两个陈述:

explain select * from T where payload->'business'->'taxId' @> '"123456789"'; (1)
explain select * from T where payload->'stakeholders'->'person'->'taxId' @> '"123456789"'; (2)

第一个语句是使用索引。但第二个是进行全表扫描,这非常慢。这就是为什么我们转向索引整个payload列。

欢迎提出任何建议。

顺便说一句,我们使用的是Postgres 9.5.4。

1 个答案:

答案 0 :(得分:3)

您的查询:

select * from T where payload->'stakeholders'->'person'->'taxId' @> '"123456789"';

不起作用。这是因为'利益相关者'是阵列。工作查询是:

select * from T where payload->'stakeholders' @> '[{"person": {"taxId": "54"}}]'::jsonb

但在这种情况下,postgres可以使用整个利益相关者的使用指数。

                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on t  (cost=1388.08..1425.90 rows=10 width=36) (actual time=1.959..1.959 rows=1 loops=1)
   Recheck Cond: ((payload -> 'stakeholders'::text) @> '[{"person": {"taxId": "54"}}]'::jsonb)
   Heap Blocks: exact=1
   ->  Bitmap Index Scan on t_expr_idx3  (cost=0.00..1388.08 rows=10 width=0) (actual time=1.946..1.946 rows=1 loops=1)
         Index Cond: ((payload -> 'stakeholders'::text) @> '[{"person": {"taxId": "54"}}]'::jsonb)
 Planning time: 0.071 ms
 Execution time: 1.978 ms

对于使用更具体的索引,我使用修改后的方法:How do you create a Postgresql JSONB array in array index?

CREATE OR REPLACE FUNCTION extract_taxids(a_json jsonb).
RETURNS jsonb AS $BODY$
     SELECT jsonb_agg(j) FROM (SELECT jsonb_array_elements(a_json->'stakeholders')->'person'->'taxId' AS j) AS j
$BODY$ LANGUAGE sql IMMUTABLE;
CREATE INDEX ON T USING gin (extract_taxids(payload));

和vuala:

EXPLAIN ANALYZE select * from T where extract_taxids(payload) @> '["54"]';

                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on t  (cost=12.08..52.38 rows=10 width=36) (actual time=0.101..0.102 rows=1 loops=1)
   Recheck Cond: (extract_taxids(payload) @> '["54"]'::jsonb)
   Heap Blocks: exact=1
   ->  Bitmap Index Scan on t_extract_taxids_idx  (cost=0.00..12.07 rows=10 width=0) (actual time=0.008..0.008 rows=1 loops=1)
         Index Cond: (extract_taxids(payload) @> '["54"]'::jsonb)
 Planning time: 0.128 ms
 Execution time: 0.117 ms