为什么Postgres在此查询中执行哈希?

时间:2010-06-17 20:38:55

标签: sql optimization postgresql query-optimization

我有两个表:AP。我希望从A中的所有行中获取信息,其中id位于我创建的临时表tmp_ids中。但是,AP中有关于foo的其他信息,我也希望获得此信息。我有以下查询:

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与我为A创建的H_id的索引结合在一起,并带有嵌套循环。但是,在使用第一次合并的结果进行散列连接之前,它会散列所有PP非常大,我认为这就是所有的时间。为什么会在那里创建哈希? P.idP的主键,A.P_id有自己的索引。

更新:所有数据类型都是INTEGER,但A.size除外,它是双精度,P.foo是VARCHAR。我正在使用PostgreSQL版本8.4。

以下是解释:http://explain.depesz.com/s/WBo

3 个答案:

答案 0 :(得分:3)

查询计划程序估计,按顺序读取所有数据并对其进行哈希处理要比使用相关的更多随机磁盘访问执行估计的2100索引扫描更快。

答案 1 :(得分:1)

如果没有看到解释分析,这些问题通常会导致统计信息被关闭或者random_page_cost或seq_page_cost所需的异常设置。

可能使用

更好地运行
set enable_hashjoin = false;

答案 2 :(得分:0)

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

该错误继续向它认为有2100行进行扫描,此时它可能会执行完整的顺序扫描并对结果进行散列,因为这可能会触及表中的大多数块。

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