Postgres中的高效加入

时间:2017-08-07 01:34:39

标签: sql postgresql

我有三个大表,A(1000万行),A_C(6000万行)和C(6行)。它们通过bigint字段和主要外键关系相关联。这些表具有n:m关系,这就是我添加A_C表的原因。架构如下:

A.id = A_C.a_idC.id = A_C.c_id

A是此处的主要表格。我想显示A的前100个条目以及CA_C的所有相应行。目前查询需要很长时间。我的第一种方法是两个简单的连接。运行EXPLAIN ANALYZE我发现,SQL在A上执行顺序扫描。我认为这是因为它最后应用了限制而忽略了它。这表现得非常糟糕。有没有办法解决这个LIMIT或我在这里缺少的另一种解决方案?当我在一个简单的选择查询上执行LIMIT时,它在~2ms内执行得很好。

编辑:A.id是主键并具有btree索引。 A_C对整行以及A_C.a_idA_C.c_id上的索引都有唯一约束。我还没有加入C因为它已经很慢了。

快速查询:

  • SELECT A.id FROM A
  • SELECT A.id FROM A LIMIT 10

慢查询:

以下是查询计划的快速但执行速度慢,因为数据量非常大:

  • SELECT A.id FROM A JOIN A_C ON A.id = A_C.a_id

我尝试通过设置检索A的行数限制来避免这种情况:

SELECT a.id FROM (SELECT A.id AS id FROM metrics.metrics LIMIT 10) a JOIN A_C ON (a.id = A_C.a_id)

EXPLAIN ANALYZE的查询计划如下:

"Hash Join  (cost=5.75..1305897.53 rows=44790854 width=8) (actual time=251969.648..251969.648 rows=0 loops=1)"
"  Hash Cond: (a_c.a_id = a.id)"
"  ->  Seq Scan on a_c  (cost=0.00..690017.54 rows=44790854 width=8) (actual time=0.472..126203.253 rows=44790000 loops=1)"
"  ->  Hash  (cost=4.50..4.50 rows=100 width=8) (actual time=1.889..1.889 rows=100 loops=1)"
"        Buckets: 1024  Batches: 1  Memory Usage: 12kB"
"        ->  Limit  (cost=0.00..3.50 rows=100 width=8) (actual time=0.527..1.550 rows=100 loops=1)"
"              ->  Seq Scan on a  (cost=0.00..261275.88 rows=7465088 width=8) (actual time=0.520..0.912 rows=100 loops=1)"
"Planning time: 16.350 ms"
"Execution time: 251969.693 ms"

1 个答案:

答案 0 :(得分:1)

我会为a

中的行建议一个子查询
select . . .
from (select a.*
      from a
      order by a.id
      fetch first 100 rows only    -- or limit 100
     ) a join
     a_c ac
     on ac.a_id = a.id join
     c
     on ac.c_id = c.id;

即使c非常小,但如果您还没有主键,我会鼓励c(id)使用主键。

这假设“前100行”是指主键的排序。