当前位置: 首页 > 面试题库 >

PostgreSQL解释计划中的成本计量有多可靠?

袁雅逸
2023-03-14
问题内容

查询在具有1100万行的大型表上执行。在执行ANALYZE查询之前,我已经在表上执行了。

查询1:

SELECT *
FROM accounts t1
LEFT OUTER JOIN accounts t2 
    ON (t1.account_no = t2.account_no
        AND t1.effective_date < t2.effective_date)
WHERE t2.account_no IS NULL;

解释分析:

Hash Anti Join  (cost=480795.57..1201111.40 rows=7369854 width=292) (actual time=29619.499..115662.111 rows=1977871 loops=1)
  Hash Cond: ((t1.account_no)::text = (t2.account_no)::text)
  Join Filter: ((t1.effective_date)::text < (t2.effective_date)::text)
  ->  Seq Scan on accounts t1  (cost=0.00..342610.81 rows=11054781 width=146) (actual time=0.025..25693.921 rows=11034070 loops=1)
  ->  Hash  (cost=342610.81..342610.81 rows=11054781 width=146) (actual time=29612.925..29612.925 rows=11034070 loops=1)
        Buckets: 2097152  Batches: 1  Memory Usage: 1834187kB
        ->  Seq Scan on accounts t2  (cost=0.00..342610.81 rows=11054781 width=146) (actual time=0.006..22929.635 rows=11034070 loops=1)
Total runtime: 115870.788 ms

估计费用 约为120万 ,实际花费的时间 约为1.9分钟

查询2:

SELECT t1.*
FROM accounts t1
LEFT OUTER JOIN accounts t2 
    ON (t1.account_no = t2.account_no
        AND t1.effective_date < t2.effective_date)
WHERE t2.account_no IS NULL;

解释分析:

Hash Anti Join  (cost=480795.57..1201111.40 rows=7369854 width=146) (actual time=13365.808..65519.402 rows=1977871 loops=1)
  Hash Cond: ((t1.account_no)::text = (t2.account_no)::text)
  Join Filter: ((t1.effective_date)::text < (t2.effective_date)::text)
  ->  Seq Scan on accounts t1  (cost=0.00..342610.81 rows=11054781 width=146) (actual time=0.007..5032.778 rows=11034070 loops=1)
  ->  Hash  (cost=342610.81..342610.81 rows=11054781 width=18) (actual time=13354.219..13354.219 rows=11034070 loops=1)
        Buckets: 2097152  Batches: 1  Memory Usage: 545369kB
        ->  Seq Scan on accounts t2  (cost=0.00..342610.81 rows=11054781 width=18) (actual time=0.011..8964.571 rows=11034070 loops=1)
Total runtime: 65705.707 ms

估计费用 约为120万( 但是 ), 但是实际花费的时间 少于1.1分钟

查询3:

SELECT *
FROM accounts
WHERE (account_no,
       effective_date) IN
    (SELECT account_no,
            max(effective_date)
     FROM accounts
     GROUP BY account_no);

解释分析:

Nested Loop  (cost=406416.19..502216.84 rows=2763695 width=146) (actual time=31779.457..917543.228 rows=1977871 loops=1)
  ->  HashAggregate  (cost=406416.19..406757.45 rows=34126 width=43) (actual time=31774.877..33378.968 rows=1977425 loops=1)
        ->  Subquery Scan on "ANY_subquery"  (cost=397884.72..404709.90 rows=341259 width=43) (actual time=27979.226..29841.217 rows=1977425 loops=1)
              ->  HashAggregate  (cost=397884.72..401297.31 rows=341259 width=18) (actual time=27979.224..29315.346 rows=1977425 loops=1)
                    ->  Seq Scan on accounts  (cost=0.00..342610.81 rows=11054781 width=18) (actual time=0.851..16092.755 rows=11034070 loops=1)
  ->  Index Scan using accounts_idx2 on accounts  (cost=0.00..2.78 rows=1 width=146) (actual time=0.443..0.445 rows=1 loops=1977425)
        Index Cond: (((account_no)::text = ("ANY_subquery".account_no)::text) AND ((effective_date)::text = "ANY_subquery".max))
Total runtime: 918039.614 ms

估计费用 约为502,000, 但实际花费的时间 约为15.3分钟!

  • EXPLAIN输出的可靠性如何?
  • 我们是否总是EXPLAIN ANALYZE要看看我们的查询将如何在真实数据上执行,而 不是信任 查询计划者 认为 它会花费多少?

问题答案:

它们是可靠的,除非不是。您无法真正概括。

看来它大大低估了它将发现的不同account_no的数量(认为它将发现34126实际上是在1977425找到的)。您的default_statistics_target可能不够高,无法获得此列的良好估算值。



 类似资料:
  • 版本生命周期 版本 状态 积极支持截止时间 安全维护截止时间 发布或预计发布时间 3.0 研发中 / / 2021-06-20 2.1 积极支持中 / / 2020-12-28 2.0 安全维护中 2020-12-28 2021-06-30 2020-06-22 1.1 停止维护 2020-06-23 2020-12-31 2019-10-08 1.0 停止维护 2019-10-08 2019-1

  • 问题内容: 我想知道如何使用Java获取解释计划。我之所以需要它,是因为我们有一个特殊用户可以编写报告的框架。这些报告有时会生成大量查询,我们想在其中动态解释并存储其成本。这样,我们可以稍后分析高成本查询并进行优化。 给我非法列异常的示例代码: 问题答案: 用这个:

  • 我有计划 每天给自己一个目标 每天都面对自己的梦想 每天都是生命中最早的一天 把每天当做最后一天来过 每天不断鞭策自己做得更好 拿出魄力 活出激情 坚持对每个人都很重要 不放弃,不妥协 目标就在前方 理想生活,我有计划 应用名称:我有计划 说明:现在应用的功能还过于简单,希望感兴趣的朋友们可以提供一些精品功能点子。可以看到自己提供的功能点子被实现在应用里供很多人使用和喜欢,也是一件让人兴奋的事情。

  • 当我尝试构建项目时。生成失败,出现以下消息。 我看到了两个类似的问题,并尝试了答案中提到的一切。 我尝试过的事情。

  • 我有一个简单的计划任务,它是使用@计划注释创建的。类似这样的东西- 我还有一个蓝绿色升级场景,在这个场景中,这个计划任务可能会在蓝色和绿色集群中运行。鉴于这个计划任务修改了数据库,其中一个节点可能会覆盖来自另一个节点的数据——或者最坏情况下的竞争条件。 我想暂停绿色集群上所有计划的任务,直到它准备好接受流量。我已经有了代码来监听应用程序状态的变化。 我探索了几个选择- 只需在任务开始时添加一个布尔

  • 我正在使用Spring MVC,我正在尝试编写一个每小时运行一次的计划任务。问题是,当应用程序启动时,它应该计算到下一个小时的持续时间,并将该值用作初始延迟。这样,计划的任务可以在精确的时间运行,比如下午1点。。。下午2点。。。下午三点等等。 在下面的代码中,我试图计算@PostConstruct注释中的初始延迟。但是,当我尝试在@Sched的注释中使用变量时,会收到以下错误消息:注释属性Sche