2011-03-31 26 views
1

我有兩個表的訂單,並與下面的結構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屬於Orders其中給定的產品是唯一訂購的產品。 E.g:如果user_id是1和的product_id爲1,查詢應返回行項目5和7

  • 給定一個userproduct找到Orders這裏給出的產品是有序的唯一產品。 E.g:如果user_id是1和的product_id爲1,查詢應返回的訂單3和5

訂單和了LineItem表可以有幾百萬行的。

我有一個工作解決方案,使用COUNTHAVING。我不確定這是最有效的解決方案。

具體而言,我想知道這是否可以通過使用Cletusthis answer中概述的技術來解決。

說明: 我正在使用Orders和LineItems表來描述場景。我實際的表是完全不同的,它不涉及到訂單等

編輯2

這是查詢比使用GROUP BYHAVING高效?

SELECT A.id 
FROM LineItems A 
JOIN Orders B ON B.id = A.order_id AND B.user_id = 1 
LEFT OUTER JOIN LineItems C ON C.order_id = A.order_id AND 
           C.product_id != A.product_id 
WHERE A.product_id = 1 AND C.id IS NULL 
+0

聽起來像'HAVING COUNT(...)'的教科書案例 – Phil 2011-03-31 02:51:11

+0

我確實有基於'HAVING'和'COUNT'的解決方案。我不確定這是否是最有效的解決方案。 – 2011-03-31 02:52:22

+0

我知道,我在說你當前的方法是合理的(請參閱zerkms的答案中的注意事項) – Phil 2011-03-31 02:53:51

回答

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。

索引你NEED有:orders.user_idlineitems.order_id

+0

我需要分別訪問訂單ID和訂單項ID,因爲我使用查詢來選擇要刪除的候選行。我用我正在考慮的解決方案更新了我的問題。讓我知道你的想法。 – 2011-03-31 05:12:16

+0

@KandadaBoggu - 如果你只需要其中的一個,你可以從SELECT子句中移除另一個;我正是這個意思。您的修改後的查詢是一種替代方法,因爲它總是取決於數據的分佈,所以沒有明確的「更快」的查詢。每個訂單的平均線數。嘗試兩者並使用更快的產品 – RichardTheKiwi 2011-03-31 05:30:11

+0

我希望每個訂單有1-5個訂單項,而用戶+產品組合需要100個數量的訂單項。 – 2011-03-31 05:36:19

0

如果你真的有龐大的項目和數據的真正海量那麼這將是最好有「類似商品」被預先計算,並通過一些調度(每天一次,一小時,每週更新,.. )或者一些「觸發器」(添加新的好東西后)。

無法使您提到的查詢(使用COUNT + HAVING + GROUP BY)具有高性能。

+0

我正在使用Orders和LineItems表來描述場景。我的實際表格是完全不同的,它與秩序等無關。 – 2011-03-31 02:56:13

+0

@KandadaBoggu:那又如何? ;-)主要思想是:如果你不能優化查詢(或者不可能;是的,有這種情況),那麼它可以是預先計算數據的解決方案。 – zerkms 2011-03-31 02:57:31

+0

具體而言,我想知道這是否可以通過在這個答案中使用'Bill'概述的技術來解決http://stackoverflow.com/questions/477006/sql-statement-join-vs-group-by-and-having/477035#477035。 – 2011-03-31 03:07:56

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 
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)。分組(on order_id)在內部仍然需要,但計數可以省略。 (一旦遇到第一個重複的order_id,子查詢可以返回false)