【问题标题】:Using materialized views to improve jsonb indexing and querying使用物化视图改进 jsonb 索引和查询
【发布时间】:2021-06-23 15:19:35
【问题描述】:

拥有 RDS Postgresql 12.5 并处理带有 JSONB 列 (metadata) 的表 (app_events),JSON 数据可能会因事件名称而异,请参阅下面的结构。

CREATE TABLE IF NOT EXISTS "public".app_events (
    id uuid DEFAULT uuid_generate_v4() NOT NULL,
    event_id text NOT NULL,
    name text NOT NULL,
    creation_time timestamp without time zone NOT NULL,
    creation_time_in_milliseconds bigint NOT NULL,
    metadata jsonb NOT NULL,
    PRIMARY KEY(id)
);

event_idname 上有默认索引 (btree)。

基于name 列,我们创建视图以将 JSON 中的数据标准化为表格格式,示例如下。

CREATE OR REPLACE VIEW "public".charity_created AS
 SELECT app_events.id,
    app_events.event_id,
    app_events.name,
    app_events.creation_time,
    date(app_events.creation_time) AS created_date,
    (app_events.metadata ->> 'aggregateId'::text) AS user_id,
    (app_events.metadata ->> 'url'::text) AS url,
    (app_events.metadata ->> 'name'::text) AS charity_name,
    (app_events.metadata ->> 'about'::text) AS charity_about,
    (app_events.metadata ->> 'country'::text) AS country,
    (app_events.metadata ->> 'category'::text) AS category,
    (app_events.metadata ->> 'currencyCode'::text) AS currencycode,
    (app_events.metadata ->> 'isPayItForwardPartner'::text) AS is_pay_it_forward_partner,
    (app_events.metadata ->> 'isCampaignDonationPartner'::text) AS is_campaign_donation_partner
   FROM public.app_events
  WHERE (app_events.name = 'CharityCreated'::text)
  ORDER BY (date(app_events.creation_time)) DESC;

现在您可以运行如下查询。

SELECT * 
FROM "public".charity_created
WHERE charity_name == 'some_charity_name'

此外,我们在视图之间创建连接或联合,并开始注意到读取/查询的延迟有时长达一小时,没有超时,但返回数据可能具有挑战性,这对我们的报告团队来说绝对是一个巨大的打击。

我正在寻找的问题和知识是,我可以在哪里创建(或应该创建)索引以改善读取延迟;到目前为止有两个发现进行辩论。

  1. 在实际的 JSONB 列 (metadata) 上没有意义,因此也许一种解决方案是开始根据每个事件名称的特定架构创建索引,例如 this answer
  2. 创建materialized views并付出代价刷新数据副本(每晚),同时在物化视图上创建索引,类似于this answer
  3. 也许保留views 并在这些上创建索引

【问题讨论】:

    标签: postgresql indexing jsonb materialized-views


    【解决方案1】:

    您可以尝试使用以下表达式的索引:

    CREATE INDEX app_events_charity_name_idx ON app_events USING(metadata ->> 'name'::text);
    

    在查询中(完全)使用表达式时,可能会使用此索引,例如:

    SELECT * FROM app_events WHERE metadata ->> 'name'::text = 'some charity';
    

    这也应该适用于您的视图。但是您应该使用EXPLAIN 进行检查。

    在较新版本的 Postgres 中,还可以使用 generated columns。与物化视图相比,它们的优点是您不必担心更新它们。

    ALTER TABLE app_events ADD charity_name TEXT GENERATED ALWAYS AS (metadata ->> 'name'::text);
    

    您也可以为这些列创建索引。

    【讨论】:

    • 第一个选项可能是要走的路。我们确实查询了视图列,尽管它几乎是索引为 AS column_name 的表达式,你认为这应该工作吗?我没有得到解释部分。
    • 我想我应该在创建索引上添加 NOT NULL;因为每个事件名称的 JSON 模式总是不同的。
    • 你绝对应该调查它。有时优化器可以发挥意想不到的惊喜。您将如何在索引定义中指定 NOT NULL?我也不明白这与架构有何关系。
    • 我在这里看到了 stackoverflow.com/a/36076895/122769。 CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)) WHERE (animal ->> 'cow') IS NOT NULL;
    • 这是部分索引。如果 NULL 的数量很大,这是有道理的,但通常您必须将该条件包含在查询中,以便使用索引。
    猜你喜欢
    • 2011-05-15
    • 2017-05-19
    • 2016-05-08
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 2016-08-25
    • 2019-12-22
    • 1970-01-01
    相关资源
    最近更新 更多