为什么Postgres扫描一个巨大的表而不是使用我的索引?

时间:2014-04-17 21:07:12

标签: sql performance postgresql indexing sql-execution-plan

我注意到我的一个SQL查询比我预期的要慢得多,事实证明查询计划程序正在制定一个对我来说非常糟糕的计划。我的查询如下:

select A.style, count(B.x is null) as missing, count(*) as total
  from A left join B using (id, type)
  where A.country_code in ('US', 'DE', 'ES')
  group by A.country_code, A.style
  order by A.country_code, total

B具有(type,id)索引,A具有(country_code,style)索引。 A远小于B:A中的250K行与B中的100M行。

所以,我希望查询计划看起来像:

  • 使用A上的索引仅选择具有相应country_code
  • 的行
  • 与B联系左边,根据(type, id)索引找到匹配的行(如果有的话)
  • 根据country_codestyle
  • 对内容进行分组
  • 添加点数

但查询计划程序决定执行此操作的最佳方法是对B进行顺序扫描,然后对A进行右连接。我无法理解为什么会这样;有没有人有想法?这是它生成的实际查询计划:

 Sort  (cost=14283513.27..14283513.70 rows=171 width=595)
   Sort Key: a.country_code, (count(*))
   ->  HashAggregate  (cost=14283505.22..14283506.93 rows=171 width=595)
         ->  Hash Right Join  (cost=8973.71..14282810.03 rows=55615 width=595)
               Hash Cond: ((b.type = a.type) AND (b.id = a.id))
               ->  Seq Scan on b (cost=0.00..9076222.44 rows=129937844 width=579)
               ->  Hash  (cost=8139.49..8139.49 rows=55615 width=28)
                     ->  Bitmap Heap Scan on a  (cost=1798.67..8139.49 rows=55615 width=28)
                           Recheck Cond: ((country_code = ANY ('{US,DE,ES}'::bpchar[])))
                           ->  Bitmap Index Scan on a_country_code_type_idx  (cost=0.00..1784.76 rows=55615 width=0)
                                 Index Cond: ((country_code = ANY ('{US,DE,ES}'::bpchar[])))

编辑:根据另一个问题的评论提示,我尝试使用SET ENABLE_SEQSCAN TO OFF;,查询运行速度提高了十倍。显然我不想永久禁用顺序扫描,但这有助于确认我没有根据的猜测顺序扫描不是最好的可用计划。

2 个答案:

答案 0 :(得分:4)

如果您的添加测试证明了索引扫描的查询实际上更快,那么它通常是其中一个或两个:

  • 您的统计信息已关闭或不够精确,无法涵盖不规则的数据分发。
  • 您的费用设置已关闭,Postgres将其用作成本估算的基础。

这个密切相关的答案的详情:

答案 1 :(得分:0)

也许你的db有权利。看起来第一个过滤器有55k匹配的行。运行此数量的索引扫描迭代可能非常耗时。 通常,散列连接对于不那么有选择性的东西来说更快。

无论如何,你可以尝试一些事情:

  • 删除左侧关键字并使用内部联接。
  • 分析你的桌子。