【问题标题】:Why is Postgres doing a Hash in this query?为什么 Postgres 在这个查询中做一个哈希?
【发布时间】:2011-03-05 04:10:33
【问题描述】:

我有两张桌子:AP。我想从A 中的所有行中获取信息,这些行的id 位于我创建的临时表tmp_ids 中。但是,在Pfoo 中有关于A 的其他信息,我也想获得这些信息。我有以下查询:

SELECT A.H_id AS hid,
       A.id AS aid,
       P.foo, A.pos, A.size
FROM tmp_ids, P, A
WHERE tmp_ids.id = A.H_id
  AND P.id = A.P_id

我注意到它运行缓慢,当我要求 Postgres 解释时,我注意到它结合了 tmp_ids 和我为 H_id 创建的 A 上的索引和嵌套循环。但是,它会在与第一次合并的结果进行哈希连接之前对所有 P 进行哈希处理。 P 相当大,我认为这一直是需要的。为什么它会在那里创建一个哈希? P.idP 的主键,A.P_id 有自己的索引。

更新:所有数据类型都是整数,除了 A.size 是双精度和 P.foo 这是 VARCHAR。我使用的是 PostgreSQL 8.4 版。

这里是解释:http://explain.depesz.com/s/WBo

【问题讨论】:

  • 您可能必须明确声明连接字段的数据类型
  • 发布解释分析,或者更好的是,在explain.depesz.com 上发布解释并提供链接。还有,什么PG版本?
  • 使用一些 DBMS,您可以强制循环连接,但我认为 PostrgresSQL 不可能。这有点可惜,因为在很多情况下,优化器无法计算出像您这样的数据现实。
  • @Pointy 您可以“设置 enable_hashjoin = false”,在这种情况下可能会这样做。
  • 嗯,我意识到它正在散列的表 P 只有 43000 个条目,所以也许这不是查询运行缓慢的原因.. 可能是程序的另一部分

标签: sql optimization postgresql query-optimization


【解决方案1】:

查询规划器估计顺序读取所有数据并对其进行散列处理比执行估计的 2100 次索引扫描以及相关的随机磁盘访问要快。

【讨论】:

    【解决方案2】:

    在没有看到解释分析的情况下,这类问题通常是由于统计信息关闭或 random_page_cost 或 seq_page_cost 所需的异常设置造成的。

    可能运行得更好

    set enable_hashjoin = false;
    

    【讨论】:

    • 当你这样做时,优化器会做一个合并连接。仍然不是最优的,因为它必须在匹配之前先对键进行排序。我想要索引驱动的嵌套循环。您可能想要设置 enable_hashjoin = true 并尝试将每个 postgresql.org/docs/current/static/… 的 work_mem、maintainance_work_mem(以及 shared_buffers)设置为更小的大小。有时优化器认为有足够的内存,它每次都会做哈希连接。
    【解决方案3】:

    您的问题是优化器没有正确的统计信息来确定要创建多少匹配“A.H_id = tmp_ids.id”,这是临时表的常见问题——它们没有像普通人一样进行统计。它猜测从“使用 A 上的 idx_A_handid 进行索引扫描”出来的 21 行将匹配,但实际上只有 3 行。它在解释分析中突出显示,其中最低级别的向上箭头旁边有一个 7,给出估计错误程度的乘数。

    该错误会延续到它认为有 2100 行要扫描的地方,此时它可能会执行完整的顺序扫描并对结果进行哈希处理,因为这可能会触及表中的大多数块。

    如果它正确地知道只有 300 个要探测,它可能会做一些不同的事情,只涉及数据的一个子集。由于缺乏统计信息,您不能指望从针对临时表的连接中获得好的计划。在这种情况下,在执行查询之前关闭 enable_hashjoin 来推动正确的行为可能是合适的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-30
      • 1970-01-01
      • 1970-01-01
      • 2017-10-26
      • 2010-11-01
      • 2015-12-04
      • 2021-12-12
      • 2011-06-04
      相关资源
      最近更新 更多