【问题标题】:Optimizing bulk update with two inner joins and calculation使用两个内连接和计算优化批量更新
【发布时间】:2016-04-01 16:32:18
【问题描述】:

所以我有三个表: 产品、优惠和offer_lines

offer_lines 是一个连接表,用于建立一个拥有和属于多个关系:

  • 产品 has_many offer_lines
  • offers has_many offer_lines

offer_lines 有一个名为 calculated_price 的列。这是基于 offer 表的列 discount_percentage 和 products 表的列 price

我想创建一个sql语句,可以根据offers表中存储的折扣百分比计算产品的折扣价格。

这是我目前得到的:

UPDATE offer_lines
SET discounted_price = (products.price - (products.price * offers.discount_percentage / 100))
FROM offer_lines AS o
  INNER JOIN products ON o.product_id = products.id
  INNER JOIN offers ON o.offer_id = offers.id
WHERE offer_lines.offer_id = 2;

这似乎工作正常,只是它需要大约一分钟才能运行。

这里是解释:

Update on offer_lines  (cost=77.16..1131.37 rows=10670 width=87)
  ->  Hash Join  (cost=77.16..1131.37 rows=10670 width=87)
    Hash Cond: (o.product_id = products.id)
    ->  Hash Join  (cost=9.44..836.90 rows=10670 width=77)
          Hash Cond: (o.offer_id = offers.id)
          ->  Seq Scan on offer_lines o  (cost=0.00..620.74 rows=26674 width=14)
          ->  Hash  (cost=9.38..9.38 rows=4 width=71)
                ->  Nested Loop  (cost=0.29..9.38 rows=4 width=71)
                      ->  Index Scan using index_offer_lines_on_offer_id on offer_lines  (cost=0.29..8.30 rows=1 width=53)
                            Index Cond: (offer_id = 13)
                      ->  Seq Scan on offers  (cost=0.00..1.04 rows=4 width=18)
    ->  Hash  (cost=62.88..62.88 rows=388 width=18)
          ->  Seq Scan on products  (cost=0.00..62.88 rows=388 width=18)

有什么想法可以让这个运行得更快吗?

【问题讨论】:

  • 桌子上有索引吗?
  • 是的,在 offer_lines offer_id 和 offer_lines product_id 上

标签: sql postgresql


【解决方案1】:

首先,Postgres 的语法不应重复 FROM 子句中正在更新的表:

UPDATE offer_lines ol
    SET discounted_price = (p.price - (p.price * o.discount_percentage / 100))
FROM products p, offers o
WHERE ol.offer_id = o.id AND
      ol.product_id = p.id AND
      ol.offer_id = 2;

(哇,我不敢相信我在FROM 子句中使用了逗号。Arrrgh。)

然后,对于这个查询,您需要offer_lines(offer_id, product_id)products(id, price)(价格是可选的)和offers(id, discount_percentage)discount_percentage 是可选的)的索引。

如果我不得不猜测性能问题是因为order_linesupdate 语句和from 子句中。

编辑:

我应该清楚。您可以FROM 子句中重复该表。但它需要绑定到正在更新的版本:

UPDATE offer_lines ol
    SET discounted_price = (p.price - (p.price * o.discount_percentage / 100))
FROM offer_lines ol2 INNER JOIN
     products p
     ON ol2.product_id = p.id INNER JOIN
     offers o
     ON ol.offer_id = o.id
WHERE ol2.offer_id = 2 AND ol.id = o.id;

这假设offer_lines 有一个主键列,我称之为id。坦率地说,就可读性而言,我可以看到以这种方式进行更新的好处。

【讨论】:

  • 并在 where 子句中添加 AND ol.discounted_price <> (p.price - (p.price * o.discount_percentage / 100)) 以避免创建不必要的行版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-16
  • 2016-04-29
  • 1970-01-01
  • 2019-03-10
  • 2016-04-27
  • 1970-01-01
  • 2019-08-07
相关资源
最近更新 更多