【问题标题】:Performance with jsonb in PostgreSQLPostgreSQL 中 jsonb 的性能
【发布时间】:2020-04-06 08:11:30
【问题描述】:

我在 postgreSQL 数据库上的 SQL 查询遇到了一些问题。

我们正在处理具有 300 000 行的表。

第一个:

SELECT DISTINCT jsonb_object_keys("verbatim_verbatim"."meta") AS "meta_key" 
FROM "verbatim_verbatim" 
WHERE "verbatim_verbatim"."group_id" = 'dd1c8016-a0ea-49bb-914b-1c036fb3b0a1'::uuid

解释:

HashAggregate  (cost=25959.68..32449.08 rows=1278700 width=32) (actual time=274.130..274.144 rows=5 loops=1)
  Group Key: jsonb_object_keys(meta)
  Buffers: shared hit=18996 read=2308
  I/O Timings: read=44.623
  ->  Seq Scan on verbatim_verbatim  (cost=0.00..25766.87 rows=77123 width=32) (actual time=0.048..209.216 rows=390000 loops=1)
        Filter: (group_id = 'dd1c8016-a0ea-49bb-914b-1c036fb3b0a1'::uuid)
        Rows Removed by Filter: 263605
        Buffers: shared hit=18996 read=2308
        I/O Timings: read=44.623
Planning time: 103.268 ms
Execution time: 274.385 ms

第二个:

SELECT COUNT(*) AS "__count" 
FROM "verbatim_verbatim" 
WHERE ("verbatim_verbatim"."group_id" = 'dd1c8016-a0ea-49bb-914b-1c036fb3b0a1'::uuid 
       AND "verbatim_verbatim"."themes" IS NOT NULL)

解释:

Aggregate  (cost=25759.21..25759.22 rows=1 width=8) (actual 

time=165.949..165.949 rows=1 loops=1)
  Buffers: shared hit=19092 read=2212
  I/O Timings: read=52.237
  ->  Seq Scan on verbatim_verbatim  (cost=0.00..25574.06 rows=74059 width=0) (actual time=0.027..161.431 rows=78000 loops=1)
        Filter: ((themes IS NOT NULL) AND (group_id = 'dd1c8016-a0ea-49bb-914b-1c036fb3b0a1'::uuid))
        Rows Removed by Filter: 263605
        Buffers: shared hit=19092 read=2212
        I/O Timings: read=52.237
Planning time: 31.154 ms
Execution time: 166.015 ms

按照评论中的建议进行真空分析:

Aggregate  (cost=25758.09..25758.10 rows=1 width=8) (actual time=120.529..120.529 rows=1 loops=1)
  Buffers: shared hit=20683 read=621
  I/O Timings: read=13.179
  ->  Seq Scan on verbatim_verbatim  (cost=0.00..25574.06 rows=73611 width=0) (actual time=0.027..116.082 rows=78000 loops=1)
        Filter: ((themes IS NOT NULL) AND (group_id = 'dd1c8016-a0ea-49bb-914b-1c036fb3b0a1'::uuid))
        Rows Removed by Filter: 263605
        Buffers: shared hit=20683 read=621
        I/O Timings: read=13.179
Planning time: 59.956 ms
Execution time: 120.595 ms

这是我的数据库:

create table verbatim_verbatim
(
    id             serial                   not null
        constraint verbatim_verbatim_pkey
            primary key,
    verbatim_id    varchar(255)             not null,
    date_interview timestamp with time zone not null,
    text           varchar(160000)          not null,
    meta           jsonb                    not null,
    themes         jsonb,
    tonality       varchar(8),
    group_id       uuid                     not null
        constraint verbatim_verbatim_group_id_717c7b4d_fk_verbatim_
            references verbatim_verbatimgroup
            deferrable initially deferred,
    constraint verbatim_verbatim_verbatim_id_group_id_8d53a593_uniq
        unique (verbatim_id, group_id)
);

create index verbatim_verbatim_verbatim_id_7e805bd5
    on verbatim_verbatim (verbatim_id);

create index verbatim_verbatim_verbatim_id_7e805bd5_like
    on verbatim_verbatim (verbatim_id);

create index verbatim_verbatim_meta_89c00a2f
    on verbatim_verbatim (meta);

create index verbatim_verbatim_group_id_717c7b4d
    on verbatim_verbatim (group_id);

您对优化这些查询有什么想法吗:/? 谢谢你的帮助!

【问题讨论】:

  • edit您的问题并添加使用explain (analyze, buffers, format text)生成的execution plan不是只是一个“简单”解释)为formatted text,并确保您防止缩进计划。粘贴文本,然后将``` 放在计划前一行和计划后一行。还请包括所有索引的完整 create index 语句以及(格式化文本,而不是屏幕截图)。
  • 除了对函数的调用之外,这个问题可能与 JSONB 没有任何关系。 WHERE 子句执行简单的过滤。如果列被索引覆盖,则查询会很快,否则会很慢。在一堆行上执行COUNT(*) 总是比为每一行计算一个函数要快。最后,DISTINCT 本质上是一个ORDER BY,然后是重复消除。它可以通过索引来加速,除非它必须处理函数结果 - 索引是使用原始数据而不是函数结果构建的。
  • 在 PostgreSQL 中,您可以索引 JSON 字段以加速查询,但 this 特定查询正在尝试对字段内容进行扁平化和排序。它不使用任何可以从 JSON 索引中受益的运算符。看起来meta 被用来代替适当的多对多关系。如果您打算在 300K 行上运行它,则必须使用正确的模式。任何其他解决方案都会 slow
  • 两者都在一秒钟内运行良好(270ms 和 166ms)。但似乎该表的统计信息不是最新的,因为优化器预计第一个查询有 1278700 行,而不仅仅是 5 行。这就是它使用 Seq Scan 的原因,而不是 group_id 上的索引。 vacuum analyze verbatim_verbatim; 有什么改变吗?
  • 与您的查询性能无关,但为什么您在(verbatim_id) 上有 两个 索引,从屏幕截图看来您也有 两个 (group_id) 的索引也是如此。不会影响查询性能,但会影响 INSERT、UPDATE 和 DELETE 语句

标签: sql postgresql jsonb


【解决方案1】:

为了计算正确的结果,它没有选择访问group_id = 'dd1c8016-a0ea-49bb-914b-1c036fb3b0a1' 所在的所有行,以便它可以检查所有键。由于您的大部分表都满足该条件,因此这不可避免地需要一些时间,而且(无论如何对于您的第一次查询)索引不太可能有太大帮助。

这看起来像是某种家务操作。为什么你运行得如此频繁以至于你关心它是否需要四分之一秒?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    • 1970-01-01
    • 2017-10-07
    • 2015-02-18
    • 2021-10-19
    • 1970-01-01
    相关资源
    最近更新 更多