提高PostgreSQL查询的效率 - 一对多,Count为1

时间:2014-09-15 19:32:03

标签: sql performance postgresql join group-by

如果可能的话,我想提高以下查询的效率:

SELECT * FROM orders o
INNER JOIN order_items oi
ON o.id = oi.order_id
WHERE o.fulfilled = false
AND o.id NOT IN (SELECT order_id
    FROM order_items
    WHERE sku = '011111'
    GROUP BY order_id
    HAVING COUNT(order_id) = 1)

订单和order_items表之间存在一对多的关系(o.id = oi.order_id)。

目标是从两个表中选择所有信息,条件如下:

  1. 订单尚未履行(orders.fulfilled = false)。

  2. 排除所有订单项目的所有订单,其中SKU为' 011111' (oi.sku喜欢' 011111')。

  3. 感谢任何帮助!

3 个答案:

答案 0 :(得分:0)

IN可以更慢,修改查询以使用内连接

select * from orders o
inner join order_items oi
on o.id = oi.order_id
and o.fulfilled = false
inner join( select order_id
    from order_items
    where sku != '011111'
    group by order_id
    having count(order_id) = 1) T
on T.order_id = oi.id

答案 1 :(得分:0)

count(whatever)通常会强制进行全表扫描(因为它不知道有多少订单按order_items分组,你不能在聚合上创建索引),除非有另一个子句可以使用指数。很可能sku不等于某些东西不够有选择性(我猜你有很多skus。)你可以查看explain输出,你可能会看到{{1}的全表扫描你查询的一部分。

如果是这种情况,那么您可以选择缓存计数数据,然后通过trigger函数对其进行索引,该函数在每次下订单或完成订单时更新IN列。或者,您可以缓存一个跟踪计数的查询(例如,如果信息不需要刷新很多。)

答案 2 :(得分:0)

我们可以假设订单在同一订单上不能有多个具有相同sku的商品吗? 我们可以假设你没有订单没有商品吗?

如果是这样,写相反的可能会更快。以下查询查找除' 011111'以外的任何sku的所有订单。此外,相关子查询通常比非相关子查询更快(尽管优化器足够聪明,可以在很多时候重写它)。 Exists子句通常比in子句更快,因为引擎可以在查看所有子查询行之前退出。

SELECT *
  FROM orders o
 INNER JOIN order_items oi
    ON o.id = oi.order_id
 WHERE o.fulfilled = false
   AND EXISTS (SELECT 'x'
                 FROM order_items oi2
                WHERE o.order_id = oi2.order_id
                  AND sku != '011111')