2014-05-22 68 views
1

我遇到了一個SQL語句與子查詢結構:子查詢導致SQL Server的無限執行

SELECT a12.ship_date  SHIP_DATE, 
     Sum(a11.qty_sold) QTY_SOLD 
FROM order_detail a11 
     JOIN order_fact a12 
     ON (a11.customer_id = a12.customer_id 
       AND a11.emp_id = a12.emp_id 
       AND a11.order_date = a12.order_date 
       AND a11.order_id = a12.order_id) 
WHERE a12.ship_date IN (SELECT DISTINCT ship_date 
         FROM order_fact 
         WHERE order_date BETWEEN (SELECT DISTINCT day_date - 1 
                FROM lu_day 
                WHERE 
           day_date = CONVERT(DATETIME, 
              '2007-01-01 00:00:00', 
              120)) AND 
                (SELECT DISTINCT day_date + 1 
                FROM 
                lu_day 
                WHERE 
           day_date = CONVERT(DATETIME, 
              '2007-01-01 00:00:00', 
              120))) 
GROUP BY a12.ship_date 

它不會停止,直到我強迫這一點。但是,如果我改變的地方進入

where a12.SHIP_DATE in ('2009-09-08 00:00:00','2009-07-08 00:00:00') 

它可以被正確執行。

我猜的原因是子查詢包含ORDER_FACT哪個列在外部查詢也依賴於它,但我不知道爲什麼。

我不熟悉SQL Server,任何人都可以解釋爲什麼會發生?謝謝。

========更新=======

謝謝你們的回答。刪除未使用的子查詢時可以更快地執行,但我仍然想知道大規模子查詢中發生了哪些瓶頸。

爲每個答案投票,因爲他們是正確的解決方案,但我認爲最好是一些執行計劃將幫助我學習更多。謝謝。

+0

它可能不是無限的......只需執行很長時間。您應該檢查解釋計劃以查看優化程序是如何決定解決查詢的。 – Frazz

+0

你能否在lu_day上解釋這些subSELECT背後的推理?他們有點模糊,因爲他們似乎在處理和返回常量。 – Frazz

+3

如果您對日期('2007-01-01')進行硬編碼,爲什麼在查詢中選擇它?你可以這樣做:'WHERE order_date在CONVERT(DATETIME,'2006-12-31 00:00:00',120)和CONVERT(DATETIME,'2007-01-02 00:00:00',120) '? – NickyvV

回答

1

不知道這會解決它,而是嘗試在子查詢更具體:

SELECT DISTINCT ship_date 
FROM order_fact OFT 
WHERE OFT.order_date BETWEEN 
    (select distinct day_date-1 
    from lu_day 
    where day_date=CONVERT(datetime, '2007-01-01 00:00:00', 120)) 
    AND 
    (SELECT DISTINCT day_date + 1 
    FROM lu_day 
    WHERE day_date = CONVERT(DATETIME, '2007-01-01 00:00:00', 120)) 

,因爲這可以更好地分離的東西。

+0

您現在缺少'BETWEEN'語句的'AND' – NickyvV

+0

我只是複製代碼,因爲它可能是稍後編輯的。但是這不應該改變這個想法。 – Louis

+0

你錯過了我的觀點。您的代碼不是有效的atm。 'BETWEEN'只有第一條語句,所以不會像'BETWEEN a AND b'。 – NickyvV

1

嘗試使用JOIN而不是IN。此外,我無法理解BETWEEN條件它相當於@NickyW提到的常量(除非該數據不存在於lu_day表中,那麼它將返回NULL)。

SELECT a12.ship_date  SHIP_DATE, 
     Sum(a11.qty_sold) QTY_SOLD 
FROM order_detail a11 
     JOIN order_fact a12 
     ON (a11.customer_id = a12.customer_id 
       AND a11.emp_id = a12.emp_id 
       AND a11.order_date = a12.order_date 
       AND a11.order_id = a12.order_id) 
     JOIN (SELECT DISTINCT ship_date 
         FROM order_fact 
         WHERE order_date BETWEEN CONVERT(DATETIME, 
              '2007-01-01 00:00:00', 
              120)) - 1 
              AND 
              CONVERT(DATETIME, 
              '2007-01-01 00:00:00', 
              120)) +1 
      ) as SHIPDATES ON a12.ship_date = SHIPDATES.ship_date 
GROUP BY a12.ship_date 
1

的查詢功能相同

SELECT a12.ship_date  SHIP_DATE, 
     Sum(a11.qty_sold) QTY_SOLD 
FROM order_detail a11 
     JOIN order_fact a12 
     ON (a11.customer_id = a12.customer_id 
       AND a11.emp_id = a12.emp_id 
       AND a11.order_date = a12.order_date 
       AND a11.order_id = a12.order_id) 
WHERE a12.ship_date BETWEEN CONVERT(DATETIME, '2007-01-01 00:00:00', 120) - 1 
         AND CONVERT(DATETIME, '2007-01-01 00:00:00', 120) + 1 
GROUP BY a12.ship_date 

a12order_fact別名所以a12.ship_date始終處於order_fact.ship_date的唯一途徑,在BETWEEN子查詢不CONVERT(DATETIME, '2007-01-01 00:00:00', 120)是,如果有在lu_day中沒有day_date,等於2007-01-01,在那種情況下它將變成

WHERE a12.ship_date BETWEEN NULL - 1 
         AND NULL + 1 

可能,因爲不會有行的子查詢

編輯
李自成查詢也許我錯了,因爲WHERE條件是在ORDER_DATE

WHERE a12.ship_date 
     IN (SELECT ship_date 
      FROM order_fact 
      WHERE order_date BETWEEN 
          CONVERT(DATETIME, '2007-01-01 00:00:00', 120) - 1 
         AND CONVERT(DATETIME, '2007-01-01 00:00:00', 120) + 1) 

如果我讀如果查詢正確,則結果將是訂單的ship date和訂單的售出數量,該訂單具有訂單的ship_date,該訂單的ship_date是在訂單的前一天和下一天之間訂購的,在這種情況下,可以放棄發貨日期的條件,在訂單當天促銷

SELECT a12.ship_date  SHIP_DATE, 
     Sum(a11.qty_sold) QTY_SOLD 
FROM order_detail a11 
     JOIN order_fact a12 
     ON (a11.customer_id = a12.customer_id 
       AND a11.emp_id = a12.emp_id 
       AND a11.order_date = a12.order_date 
       AND a11.order_id = a12.order_id) 
WHERE a12.order_date BETWEEN CONVERT(DATETIME, '2007-01-01 00:00:00', 120) - 1 
          AND CONVERT(DATETIME, '2007-01-01 00:00:00', 120) + 1 
GROUP BY a12.ship_date 

查詢的性能緊密地與索引和表的尺寸並列,例如在最後一個查詢上order_fact.order_date指數會有所幫助,並且兩個表上customer_id, emp_id, order_date, order_id指數將幫助JOIN操作。