【问题标题】:Speed up Postgres Update on Large Table加快大表上的 Postgres 更新
【发布时间】:2014-05-12 14:22:46
【问题描述】:

我有一个查询需要更新一个包含大约 1400 万条记录的表。它通过连接表从另一个表中获取需要更新的值。像这样……

UPDATE listings
SET master_ext_id = c.id
FROM listings a
    JOIN listing_to_external_id b on a.id = b.listing_id
    JOIN external_ids c on b.external_id = c.id
AND a.master_ext_id is null
AND c.provider_id = 0

Update on listings  (cost=731559.58..133068628689.23 rows=10645372213165 width=637)
  ->  Nested Loop  (cost=731559.58..133068628689.23 rows=10645372213165 width=637)
        ->  Seq Scan on listings  (cost=0.00..397447.29 rows=14832429 width=611)
        ->  Materialize  (cost=731559.58..1135721.70 rows=717709 width=26)
              ->  Hash Join  (cost=731559.58..1132133.16 rows=717709 width=26)
                    Hash Cond: (b.listing_id = a.id)
                    ->  Hash Join  (cost=148706.93..526852.10 rows=717709 width=28)
                          Hash Cond: (b.external_id = c.id)
                          ->  Seq Scan on listing_to_external_id b  (cost=0.00..236589.51 rows=15357551 width=22)
                          ->  Hash  (cost=139735.49..139735.49 rows=717715 width=14)
                                ->  Index Scan using ei_provider_id on external_ids c  (cost=0.00..139735.49 rows=717715 width=14)
                                      Index Cond: (provider_id = 0)
                    ->  Hash  (cost=397447.29..397447.29 rows=14832429 width=14)
                          ->  Seq Scan on listings a  (cost=0.00..397447.29 rows=14832429 width=14)
                                Filter: (master_ext_id IS NULL)

显然,查看执行计划,您可以看到此查询花费了非常长的时间。我现在假设它与查询中涉及的行数有关,但我需要一种方法来以某种方式加快速度。

除了 listings 表中的约 1400 万条记录外,listing_to_external_id 表中还有约 1500 万行和 external_ids 表中的约 1500 万行。

我尝试将 enable_seqscan 设置为关闭,它使用我创建的索引,所以我知道这只是计划者确定 seq 扫描会更快的情况。我还 ANALYZE'd 我的桌子。

我尝试通过使用列表表上的主键来限制更新的行,希望我能够一次循环并更新少数行。如您所见,这几乎没有影响...

UPDATE listings
SET master_ext_id = c.id
FROM listings a
    JOIN listing_to_external_id b on a.id = b.listing_id
    JOIN external_ids c on b.external_id = c.id
WHERE a.id >= 34649050
AND a.id <= 35649050
AND a.master_ext_id is null
AND c.provider_id = 0

Update on listings  (cost=212130.40..9379727588.60 rows=750294018398 width=637)
  ->  Nested Loop  (cost=212130.40..9379727588.60 rows=750294018398 width=637)
        ->  Seq Scan on listings  (cost=0.00..397447.29 rows=14832429 width=611)
        ->  Materialize  (cost=212130.40..600005.71 rows=50585 width=26)
              ->  Hash Join  (cost=212130.40..599752.78 rows=50585 width=26)
                    Hash Cond: (b.listing_id = a.id)
                    ->  Hash Join  (cost=148706.93..526852.10 rows=717709 width=28)
                          Hash Cond: (b.external_id = c.id)
                          ->  Seq Scan on listing_to_external_id b  (cost=0.00..236589.51 rows=15357551 width=22)
                          ->  Hash  (cost=139735.49..139735.49 rows=717715 width=14)
                                ->  Index Scan using ei_provider_id on external_ids c  (cost=0.00..139735.49 rows=717715 width=14)
                                      Index Cond: (provider_id = 0)
                    ->  Hash  (cost=50355.96..50355.96 rows=1045401 width=14)
                          ->  Index Scan using listings_pkey on listings a  (cost=0.00..50355.96 rows=1045401 width=14)
                                Index Cond: ((id >= 34649050) AND (id <= 35649050))
                                Filter: (master_ext_id IS NULL)

我尝试调整 Postgres 的设置以更好地处理如此大的查询,但这似乎也没有什么效果。如果对查询本身无能为力,我可以进入这些设置。

我还尝试将listing_to_external_id 和external_ids 之间的连接结果放入一个表中,对其进行索引,然后加入该表上的列表。这导致了非常相似的执行计划/成本。

目前不知道还能做什么。只需让查询在周末运行,它仍在运行。有什么建议吗?

【问题讨论】:

标签: sql database postgresql


【解决方案1】:

您使用了两次listings 表 - 一次在UPDATE 中,另一次在FROM 中。看第一个执行计划。它的笛卡尔积 (CROSS JOIN) 为listings。您只需要在UPDATE 中使用listings

试试类似的东西

UPDATE listings a
SET master_ext_id = c.id
FROM listing_to_external_id b
JOIN external_ids c on b.external_id = c.id
WHERE a.id = b.listing_id
 AND a.master_ext_id is null
 AND c.provider_id = 0

【讨论】:

  • 感谢您的回复。这很有意义。不过有一件事......你在哪里看到十字架加入计划? (请见谅,具体到 Postgres 查询计划,我有点缺乏经验。)
  • @Luke 查看计划中的顶部Nested Loop。它没有连接条件或过滤器。
  • 我明白了。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2019-04-11
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
  • 2021-05-29
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多