【发布时间】:2021-08-03 21:23:27
【问题描述】:
我正在我们的数据库中运行此查询:
select
(
select least(2147483647, sum(pb.nr_size))
from tb_pr_dc pd
inner join tb_pr_dc_bn pb on 1=1
and pb.id_pr_dc_bn = pd.id_pr_dc_bn
where 1=1
and pd.id_pr = pt.id_pr -- outer query column
)
from
(
select regexp_split_to_table('[list of 500 ids]', ',')::integer id_pr
) pt
;
它输出 500 行,只有一个结果列,运行大约需要 1 分 43 秒。 explain (analyze, verbose, buffers) 输出以下计划:
逻辑是:对于每个选择的id_pr(在 500 个 id 的列表中)计算与其关联的整数列 pb.nr_size 的总和,返回该数量与数字 2,147,483,647 之间的较小值。结果必须包含 500 行,每个 id 一行,并且我们已经知道它们将匹配子查询中的至少一行,因此不会产生空值。
索引tb_pr_dc_in05 只是id_pr 上的一个b-tree,它是整数类型。索引tb_pr_dc_bn_pk 只是主键id_pr_dc_bn 上的b-tree,它也是整数类型。表 tb_pr_dc 对于每个 id_pr 都有很多行。实际上,我们在 tb_pr_dc 中有 209,217 个唯一的 id_prs,总共 13,910,855 行。表tb_pr_dc_bn 的行数相同。
可以看出,我们定义了 500 个 id 来查询 tb_pr_dc,找到 109,468 行(不到表大小的 1%),然后在 tb_pr_dc_bn 中找到相同的数量。 Imo,索引看起来很好,要评估的行数很少,所以我不明白为什么运行这个查询要花这么多时间。许多其他查询在其他表上读取更多数据并进行更多计算运行良好。 DBA 刚刚运行了重新索引和真空分析,但它仍然以同样缓慢的方式运行。我们在 Linux 上运行 PostgreSQL 11。我在没有并发访问的副本中运行此查询。
我可能缺少什么可以提高此查询性能?
感谢您的关注。
【问题讨论】:
-
样本数据、预期结果和清晰的逻辑解释会有所帮助。
-
您需要向我们展示表和索引定义,以及每个表的行数。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。我们需要行计数,因为这会影响查询计划。
-
least(2147483647, sum(pb.nr_size))应该做什么?如果 SUM 为 NULL,您是否尝试分配一个值? COALESCE 是用于此目的的正确工具。 -
我正在编辑以解释查询的逻辑。
-
为什么是子查询?您可以在 where 子句中直接使用列表。为什么会有无用的
1=1条件?我认为您可以将查询简化为this。tb_pr_dc (id_pr, id_pr_dc_bn)和tb_pr_dc_bn (id_pr_dc_bn)上的索引应该会有所帮助
标签: sql postgresql performance query-optimization