Postgres:加快一个简单的JOIN + FILTER + ORDER BY查询操作" blocky"数据

时间:2016-04-05 09:13:44

标签: sql database postgresql

我有一个非常简单的Postgres SELECT查询,可以对两个表AB进行操作,其中A包含B&#的外键39; b_id字段中的主键:

SELECT 
    A.*, B.*
FROM
    A
INNER JOIN
    B
ON
    B.id = A.b_id 
WHERE 
    -- various conditions on A
    A.x == 3
    -- ...
    AND B.source = 'example' --source is indexed
ORDER BY
   A.created_at DESC NULLS LAST
LIMIT
    20

字段x整数),created_at日期时间)和b_id UUID A上的source以及B上的字符变化具有B树索引,b_id具有外键约束B的主键idAB的主键是随机UUID s:

Table "A"
Column       |           Type           |   Modifiers   
-------------+--------------------------+---------------
id           | uuid                     | not null
x            | integer                  |
b_id         | uuid                     | not null
created_at   | timestamp with time zone | default now()

Indexes:
     "a_pkey" PRIMARY KEY, btree (id)
     "ix_a_created_at" btree (created_at)
     "ix_a_x" btree (x)
     "ix_a_created_at_desc" btree (created_at DESC NULLS LAST)

Foreign-key constraints:
     "a_b_id_fkey" FOREIGN KEY (b_id) REFERENCES b(id)

Table "B"

Column    |           Type           |       Modifiers        
----------+--------------------------+------------------------
id        | uuid                     | not null
source    | character varying        | not null

Indexes:
    "b_pkey" PRIMARY KEY, btree (id)
    "ix_b_source" btree (source)

Postgres生成并执行以下查询计划:

Limit  (cost=0.72..4290.05 rows=20 width=122) (actual time=25801.196..25801.261 rows=20 loops=1)
   ->  Nested Loop  (cost=0.72..14553904.10 rows=67861 width=122) (actual time=25801.195..25801.252 rows=20 loops=1)
         ->  Index Scan using a_created_at_desc on a  (cost=0.43..6230611.59 rows=2200076 width=122) (actual time=0.038..21791.638 rows=2060427 loops=1)
               Filter: ((x == 3)))
               Rows Removed by Filter: 3799305
         ->  Index Scan using b_pkey on b  (cost=0.29..3.77 rows=1 width=16) (actual time=0.002..0.002 rows=0 loops=2060427)
               Index Cond: (id = a.b_id)
               Filter: ((source)::text = 'example'::text)
               Rows Removed by Filter: 1
 Total runtime: 25801.311 ms

对我而言,这似乎很好,因为Postgres使用可用的索引进行过滤和排序。

然而,问题是我的数据非常严重":表A由批处理填充,该批处理首先在B中创建一行然后数百个A中的数千个关联行。由于source值在各批次之间不同,这意味着按创建日期排序A会产生具有相同b_id值的大块行。

所以问题 - 就我所知 - 当Postgres执行嵌套循环以从A获取相关行时,它需要迭代数百万行才能击中那些行。实际上与查询相关,这使得执行非常慢(在具有数百万行的表上大于1秒)。如果我删除ORDER BY子句,查询将在几毫秒内完成,这似乎证实了这一假设。

我有什么办法可以加快速度吗?

0 个答案:

没有答案