我有两个表格订单,以及具有以下结构的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
我正在努力寻找解决以下要求的最有效方法:
鉴于user
和product
找到属于LineItems
的{{1}},其中给定的产品是唯一订购的产品。
例如:如果user_id为1且product_id为1,则查询应返回第5行和第7行。
鉴于Orders
和user
找到product
,其中给定的产品是唯一订购的产品。
例如:如果user_id为1且product_id为1,则查询应返回订单3和5.
Orders和LineItems表可以包含数百万行。
我有一个使用Orders
和COUNT
的工作解决方案。我不确定这是最有效的解决方案。
具体来说,我想知道是否可以使用this answer中HAVING
概述的技术来解决这个问题。
注意: 我使用Orders和LineItems表来描述场景。我的实际表格完全不同,与订单等无关。
修改2
此查询是否比使用Cletus
和GROUP BY
?
HAVING
答案 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_id
,lineitems.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)