高效查询以查找产品的单数订单

时间:2011-03-31 02:46:45

标签: sql

我有两个表格订单,以及具有以下结构的line_items:

Orders (id = PK, indexes on user_id)
-------------------------------------
id   user_id
==   ======
1     1
2     2
3     1
4     3
5     1

LineItems (id = PK, indexes on order_id and product_id)
id   order_id product_id quantity
==   ======   ========   ======
1      1         1       1
2      1         2       2
3      2         1       4
4      2         3       6
5      3         1       1
6      4         1       1
7      5         1       1

我正在努力寻找解决以下要求的最有效方法:

  • 鉴于userproduct找到属于LineItems的{​​{1}},其中给定的产品是唯一订购的产品。 例如:如果user_id为1且product_id为1,则查询应返回第5行和第7行。

  • 鉴于Ordersuser找到product,其中给定的产品是唯一订购的产品。 例如:如果user_id为1且product_id为1,则查询应返回订单3和5.

Orders和LineItems表可以包含数百万行。

我有一个使用OrdersCOUNT的工作解决方案。我不确定这是最有效的解决方案。

具体来说,我想知道是否可以使用this answerHAVING概述的技术来解决这个问题。

注意: 我使用Orders和LineItems表来描述场景。我的实际表格完全不同,与订单等无关。

修改2

此查询是否比使用CletusGROUP BY

更有效
HAVING

4 个答案:

答案 0 :(得分:1)

select o.id OrderID, MIN(i.id) LineItemID
from orders o
inner join lineitems i on i.order_id = o.id
where o.user_id= 1
group by o.id
having count(*)=1

GROUP BY,HAVING,COUNT对于此类查询最有效。基本上它会完全扫描所需的数据,但只能在用户的订单中扫描,但是单次传递会产生结果。

你可以一石二鸟,因为对于单个订单项的订单,min(i.id)会给你(唯一的)LineItemID。

需要的索引:orders.user_idlineitems.order_id

答案 1 :(得分:1)

select 
  * 
from 
  (
    select 
      *  
    from 
      LineItems   
    group by 
      order_id 
    having count(*) = 1 
  ) l 
    inner join Orders o on l.order_id = o.id and user_id =1 and product_id =1

答案 2 :(得分:0)

如果你有非常庞大的项目和非常庞大的数据,那么最好让“类似商品”预先计算,并由一些调度程序(每天,每小时,每周......)或某些调度程序刷新“触发”(添加新商品后)。

不可能使您提到的查询(使用COUNT + HAVING + GROUP BY)具有高性能。

答案 3 :(得分:0)

Count(*) =1很特别:您无需实际计算以检测它 例如,您可以使用NOT EXISTS来选择想要的元组:

SELECT id
FROM lineitems li
WHERE NOT EXISTS (
    SELECT *
    FROM lineitems nx
    WHERE nx.order_id = li.order_id
    AND nx.id <> li.id
    )
    ;

此(子)查询可以非常快(大多数代码生成器会将其检测为ANTI-join)。内部仍需要分组(在order_id上),但可以省略计数。 (一旦遇到第一个重复的order_id,子查询就会返回false)