2010-01-22 8 views
5

편집 1 (설명) : 지금까지 답변 해 주셔서 감사합니다. 응답은 만족 스럽습니다.
답변에 기반하여 문제의 한 가지 측면을 올바르게 설명하지 못했기 때문에 질문을 명확히하고 싶습니다. (혼자 힘겨운 시간을 정하는 데있어 그것이 내 잘못이라고 생각합니다.)
문지름 : 결과 집합에는 '2010-01-03'및 '2010-01-09'사이의 스탬프 만있는 레코드와 레코드 중 하나가 있어야합니다. 여기서 첫 번째 레코드의 각 order_num에 대해 tstamp는 NULL입니다. (항상은 각 order_num에 대해 null tstamp가됩니다.)
에 '2010-01-03'및 '2010-01-09'사이의 값이있는 경우 특정 order_num에 대한 레코드가 모두 표시됩니다. 예를 들어, order_num = 2이고 tstamp = 2010-01-12 00:00:00 인 다른 레코드가있는 경우 이 아니고이 결과에 포함되어야합니다."A UNION (B in A)"를 사용하는 것보다 효율적인 SQL?

원래 질문 :
은 ID (고유 한), order_num, tstamp (타임 스탬프)를 포함하는 주문 테이블을 고려하고, (하나의 항목이 주문에 포함) ITEM_ID. 순서가 수정되지 않은 경우 tstamp는 null이며,이 경우 동일한 order_num을 가진 다른 레코드가 있고 tstamp에 변경이 발생한 시간 소인이 포함됩니다.

예 ...

 
id order_num tstamp    item_id 
__ _________ ___________________ _______ 
0   1       100 
1   2       101 
2   2 2010-01-05 12:34:56  102 
3   3       113 
4   4       124 
5   5       135 
6   5 2010-01-07 01:23:45  136 
7   5 2010-01-07 02:46:00  137 
8   6       100 
9   6 2010-01-13 08:33:55  105 

특정 날짜 범위 동안 한 번 이상 수정 된 (order_num 기준) 모든 주문을 검색 할 수있는 가장 효율적인 SQL 문은 무엇입니까

? 즉, 각 주문에 대해 동일한 order_num (NULL tstamp가있는 레코드 포함)이 포함 된 모든 레코드가 필요합니다. 각 order_num에 대해 order_num 중 하나 이상이 tstamp NOT NULL이고 tstamp BETWEEN '2010-01-03' AND '2010-01-09'. order_num 중 적어도 하나가 tstamp NOT NULL을 가지고있는 곳입니다. 제가 어려움을 겪고 있습니다.

 
id order_num tstamp    item_id 
__ _________ ___________________ _______ 
1   2       101 
2   2 2010-01-05 12:34:56  102 
5   5       135 
6   5 2010-01-07 01:23:45  136 
7   5 2010-01-07 02:46:00  137 

기본적으로 "A UNION (A에서 B)"입니다 I는이와 함께 제공되는 SQL을,하지만 천천히 실행하고 내가 거기에 희망 :

결과 집합은 다음과 같아야합니다 보다 효율적인 솔루션입니다 :

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09') 
    AS history_orders 
UNION 
SELECT current_orders.order_id, current_orders.tstamp, current_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp IS NULL) 
    AS current_orders 
WHERE current_orders.order_id IN 
    (SELECT orders.order_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 
+0

제공된 쿼리의 성능에 대해 궁금합니다. 테스트 결과를 공유 할 수 있습니까? –

+0

곧 최종 해결책의 성능 향상에 대해보고 할 예정입니다. 이는 중요합니다. – machinatus

답변

0

모든 제안 사항에 다시 한 번 감사드립니다. 내 원본을 포함하여 작동하는 세 가지 솔루션을 찾았습니다. 마지막에는 성능 결과를 추가했습니다. 이는 내가 기대했던 것만 큼 큰 것은 아닙니다. 누군가가 이것에 향상시킬 수있는 경우에 나는 오싹 될 것입니다!

1) 지금까지 발견 된 가장 좋은 방법은 것 같습니다 :

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09' 
    OR orders.tstamp IS NULL) 
    AS history_orders 
WHERE history_orders.order_id IN 
    (SELECT orders.order_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 

2) 나는 또한 추가가 필요 IN의 장소에 존재하여 시도 WHERE 마지막 SELECT에 절 :

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09' 
    OR orders.tstamp IS NULL) 
    AS history_orders 
WHERE EXISTS 
    (SELECT orders.order_id 
    FROM orders 
    WHERE history_orders.order_id = orders.order_id 
    AND orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 

3) 마지막으로 UNION을 사용하여 내 원래 솔루션이 있습니다.

댓글 :
테이블의 크기에 대해 언급하려면, 내 실제 "현실 세계"문제는 각각 98, 2189, 43897, 785656 기록을 포함 (조인 내부와 연결) 4 개 테이블을 포함한다.

실적 - 나는 각 솔루션을 세 번 실행하고 여기 내 실제 결과입니다
1 : 52, 51, 51초
2 : 54, 54, 53의
3 : 56, 56, 56 개의

+0

order_id 및 tstamp에 대한 색인이 있습니까? –

+0

아니요. 핵심 보고서가 아니기 때문에 디자인을 수정할 권한이 없습니다. 그것은 자주 실행되지 않을 것이므로 나는 현재 가지고있는 것에 상당히 만족하고 있습니다. 아니, 나는 더 많은 것들을 향상시킬 수있는 방법에 관심이 없다. – machinatus

3

아마도 하위 쿼리 :

select * from order o where o.order_num in (select distinct 
    order_num from order where tstamp between '2010-01-03' and '2010-01-09') 
+0

첫 번째 3 개의 거의 동일한 솔루션 중에서 가장 판독하기 쉬운 +1입니다. – egrunin

+0

내 원래 질문에 내 명확한 ("편집 1") 기반으로 필요한 변경 내용을 포함시킨 후 내 솔루션은이 결과를 로 제한하는 WHERE 절을 사용하여 하위 쿼리를 추가하는 동안이 대답을 사용합니다. tstamp bethween ' 2010-01-03 'AND'2010-01-09 ' OR tstamp가 NULL입니다. 곧 완전하고 정확한 답변을 추가하겠습니다. – machinatus

1

내가하지 않았다면 misund erstood,이 같은 트릭을 수행해야합니다 EXISTS 사용

SELECT o1.id, o1.order_num, o.tstamp, o.item_id 
FROM orders o1 
WHERE EXISTS(
    SELECT * FROM orders o2 
    WHERE o1.order_num = o2.order_num 
     AND o2.tstamp BETWEEN '2010-01-03' AND '2010-01-09') 

이점은 그것이 벌금 첫 번째 일치하는 즉시 중지한다는 것입니다.

0

희망 사항이 맞습니다. 이것은 제공된 타임 스탬프 내에서 변경된 주문에 대한 모든 주문을 반환해야합니다.

SELECT o.order_id, o.tstamp, o.item_id 
FROM orders o 
JOIN (SELECT DISTINCT o2.order_num 
     FROM orders o2 
     WHERE o2.tstamp BETWEEN '2010-01-03' AND '2010-01-09') o3 
ON (o3.order_num = o.order_num) 
0

테이블을 자기 조인 할 수 있습니다.단순화 된 결과는 다음과 같습니다.

select order_id 
from orders all_orders 
inner join orders not_null_orders 
    on all_orders.order_id = not_null_orders.order_id 
where 
    not_null_orders.tstamp is not null 
    and all_orders.tstamp between '2010-01-03' AND '2010-01-09' 
1

replyping이 매우 늦었지만이 게시글을 보았을 때이 쿼리를 사용하면 위의 모든 솔루션과 비교해 볼 때 실제로 매우 작고 목적을 해결할 수있을 것이라고 생각했습니다.

select * from orders_gc where order_num in 
    (select order_num 
    from orders_gc 
    group by order_num 
    having count(id) > 1 and 
    MAX(tstamp) between '03-jan-2010' and '09-jan-2010')