2013-05-01 147 views
3

我正在使用mssql server 2008r2。 我有一個巨大的表,其中包含19個商店的營業額數據日復一日的項目。它有大約1億行。但使用分區視圖很容易運行查詢。MSSQL查詢運行緩慢,大量的LEFT JOIN

表的結構是這樣的:

  1. 店鋪名稱
  2. 項目編號
  3. 日期
  4. 週轉
  5. Selled量

輸出報告看起來像此: 商品ID,日期,商店_1 .turnover,store_1.quantity,store_2.turnover,store_2.quantity ....

要創建這種報表的我用這個查詢:

WITH cte_sell AS(
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418') 

SELECT a.item_id,a.date, 
    store_1.turnover,store_1.quantity, 
    store_2.turnover,store_2.quantity, 
    store_3.turnover,store_3.quantity 

FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a 
LEFT JOIN (SELECT * FROM cte_sell WHERE store='Store 1') as Store_1 ON a.item_id=store_1.item_id and a.date=store_1.date  
LEFT JOIN (SELECT * FROM cte_sell WHERE store='Store 2') as Store_2 ON a.item_id=store_2.item_id and a.date=store_2.date  
LEFT JOIN (SELECT * FROM cte_sell WHERE store='Store 3') as Store_3 ON a.item_id=store_3.item_id and a.date=store_3.date 

我希望你能理解查詢。

對於14-15商店(14 15 LEFT JOIN),查詢運行時間少於10秒,這很好。 但問題是,當我選擇所有的19商店(19左連接)查詢顯着減慢。完成可能需要2或3分鐘。

執行計劃的創建是太多長:

  • 12只存儲2秒
  • 19店22秒

你怎麼想,是否有任何限制表加入? 我認爲有一些服務器參數控制巨大的查詢。 有沒有人有任何想法如何優化查詢或服務器?

最糟糕的是,服務器有時會凍結:我在9點和12點運行查詢時創建了一個跟蹤文件。在9分鐘,運行查詢需要2分鐘。 在12我有tor 10分鐘後重新啓動comupetr,因爲我無法從配置管理器重新啓動SQL服務。

我不能附加screnshots。

在活動監視器中,進程處於掛起狀態。 等待類型是:CXPACKET 等待資源是:交換.... 對不起,但我不太瞭解鎖。

我試圖從管理工作室連接,我得到這個消息:連接成功地建立與服務器,但然後在登錄過程中發生錯誤。 (提供程序:TCP提供程序,錯誤:0(從匈牙利語翻譯):現有連接被強制關閉的遠程計算機

+0

執行計劃是否指出任何問題區域? – valverij 2013-05-01 15:58:27

回答

0

我相信問題是SQL Server似乎並沒有優化CTE表達式,當它們出現多個在查詢中有多少次,換句話說,如果你查看執行計劃,視圖將被執行三次 - 對於每個提及存儲。

您可以將每個商店放在不同的行上嗎?如果是的話,試試這個:

WITH cte_sell AS (
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418' 
    ) 
SELECT a.item_id, a.date, store, turnover, quantity 
FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a left join 
    cte_sell cs 
    on a.item_id=cs.item_id and a.date=cs.date and cs.store in ('Store 1', 'Store 2', 'Store 3') 

如果你需要一個行與多個商店,然後有條件的聚集或pivot將解決這個問題。

如果你想看到全部的行的值,然後使用上述查詢條件的聚集:

WITH cte_sell AS (
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418' 
    ) 
SELECT a.item_id, a.date, 
     max(case when store = 'Store 1' then turnover end), 
     max(case when store = 'Store 1' then quantity end), 
     max(case when store = 'Store 2' then turnover end), 
     max(case when store = 'Store 2' then quantity end), 
     max(case when store = 'Store 3' then turnover end), 
     max(case when store = 'Store 3' then quantity end) 
FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a left join 
    cte_sell cs 
    on a.item_id=cs.item_id and a.date=cs.date and cs.store in ('Store 1', 'Store 2', 'Store 3') 
group by a.item_id, a.date 
+0

你好! 謝謝你的回答!不幸的是,用戶想要看到所有商店的一排。我的情況下主軸不是一個好的解決方案,因爲我有一些字符類型值(我沒有提到),這是無法概括的。 – Tomi7979 2013-05-02 07:28:51

1

你有沒有考慮去除子查詢和只用加盟條件是什麼?

WITH cte_sell AS(
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418') 

SELECT a.item_id,a.date, 
    store_1.turnover,store_1.quantity, 
    store_2.turnover,store_2.quantity, 
    store_3.turnover,store_3.quantity 

FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a 
LEFT JOIN cte_sell as Store_1 ON a.item_id=store_1.item_id and a.date=store_1.date and Store='Store 1' 
LEFT JOIN cte_sell as Store_2 ON a.item_id=store_2.item_id and a.date=store_2.date and store='Store 2' 
LEFT JOIN cte_sell as Store_3 ON a.item_id=store_3.item_id and a.date=store_3.date and store='Store 3' 
+0

你好! 謝謝你的回答,我正在測試它。沒有子查詢,我覺得好多了。我也會把營業額表分成月度表(現在它包含了一年的四分之一) – Tomi7979 2013-05-02 07:23:09