使用两个内部联接和计算优化批量更新

时间:2016-04-01 16:32:18

标签: sql postgresql

所以我有三张桌子: 产品,优惠和offer_lines

offer_lines是一个连接表,用于生成并属于许多关系:

  • 产品has_many offer_lines
  • 提供has_many offer_lines

offer_lines有一个名为 calculated_price 的列。这是基于优惠表的 discount_percentage 列和产品表的价格列。

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

这是我到目前为止所得到的:

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)

我有什么想法可以让它跑得更快?

1 个答案:

答案 0 :(得分: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_lines语句和update子句中都存在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。坦率地说,就可读性而言,我可以看到以这种方式进行更新的好处。