2011-03-31 3 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이 있으며 지정된 제품은 주문한 유일한 제품입니다. 예컨대 : USER_ID가 1이고 PRODUCT_ID이 1이면 쿼리가 반환해야합니다 개별 항목 5, 7

  • user 감안할 때 주어진 제품은 주문 유일한 제품이 어디 productOrders 찾을 수 있습니다. 예컨대 : USER_ID가 1이고 PRODUCT_ID이 1이면 쿼리가 반환해야합니다 주문 3, 5

주문 및 LineItems 표는 수백만 개의 행을 가질 수 있습니다.

나는 COUNTHAVING을 사용하는 실제 해결책이 있습니다. 이것이 가장 효율적인 해결책이라고 확신하지 못합니다.

특히 에 설명 된 기술을 사용하여이 문제를 해결할 수 있는지 궁금합니다. this 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

+0

나는 HAVING 및 COUNT를 기반으로하는 해결책을 가지고 있습니다. 가장 효율적인 솔루션인지 확실하지 않습니다. –

+0

나는 현재 접근법이 합리적이라고 말하고있다. (zerkms 응답의 고려 사항 참조) – Phil

답변

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에 별도로 액세스해야합니다. 내가 고려하고있는 솔루션으로 내 질문을 업데이트했습니다. 당신이 무슨 생각을하는지 제게 알려주세요. –

+0

@KandadaBoggu - 하나만 필요하면 SELECT 절에서 다른 하나를 제거 할 수 있습니다. 그것이 내가 의미했던 것입니다. 수정 된 쿼리가 대안이며, 항상 데이터의 분포에 따라 달라 지므로 명확한 "빠른"쿼리가 없습니다. 주문 당 평균 라인. 둘 다 시도하고 더 빠른 것을 사용하십시오 – RichardTheKiwi

+0

사용자 + 제품 조합에 대해 주문 당 1-5 개의 광고 항목과 100 만 개의 광고 항목이 필요합니다. –

0

.. .) 또는 어떤 "방아쇠"(새로운 유익이 추가 된 후에).

(COUNT + HAVING + GROUP BY를 사용하여) 언급 한 쿼리를 매우 효율적으로 만들 수는 없습니다.

+0

Orders와 LineItems 테이블을 사용하여 시나리오를 설명하고있다. 내 실제 테이블은 상당히 다르며 주문 등과는 관련이 없습니다. –

+0

@KandadaBoggu : 그래서 뭐라구? ;-) 주요 아이디어는 다음과 같습니다. 쿼리를 최적화 할 수없는 경우 (또는 그렇게 할 수없는 경우) 그런 다음 데이터를 미리 계산하는 솔루션이 될 수 있습니다. – zerkms

+0

특히이 답변에서'Bill '에 기술 된 기술을 사용하여 해결할 수 있는지 궁금합니다. http://stackoverflow.com/questions/477006/sql-statement-join-vs-group-by-and-having/477035 # 477035 –

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이 원하는 튜플을 선택하기 위해 존재 사용할 수있는 감지 계산 할 필요가 없습니다 :

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

이 (하위) 쿼리 (대부분의 codegenerators는 안티 조인으로 감지합니다) 매우 빠르게 할 수 있습니다. 그룹화 (on order_id)는 여전히 내부적으로 필요하지만 카운트를 생략 할 수 있습니다. (하위 쿼리는 첫 번째 중복 order_id가 발생하면 false를 반환 할 수 있습니다.)