2017-03-15 15 views
1

2つの質問があります。SQL Server 2014 - サブクエリを使用したSUM/COUNTが複数ある

最初の部分は、私が以下でやっていることの速度です。私はデータセットを取得して、それぞれDISTINCTを取得してから、条件で合計/カウントするサブクエリに参加し、それを5回繰り返します。最初のLEFT JOINの後に02秒の実行時間があり、その後に2番目のLEFT JOINの実行時間がありますが、3番目の実行時間はLEFT JOINです。実行時間は44秒になります。そのクエリを別にして単独で実行すると、わずか1秒です。完成したクエリの合計実行時間は70秒です。

最初の部分の質問:

参加する第三に、このクエリは劇的に遅くなっていますか?

第2部:私はこれを非効率的な方法で達成していると確信しています。私はしばらく見回していましたが、各サブクエリごとに異なる基準を持つことができながら、簡単な方法でやっていることを達成する方法を見つけることができませんでした。

第2の部分の質問:

このクエリを達成するためのより良い方法はありますか?

user1413さんのコメント後にを編集します。

SELECT DISTINCTは、SQL Server実行計画ビューで49%のコストを示していました。私はSELECT DISTINCTが選択しているテーブルを変更して、実行時間が01秒以下になった。

SELECT DISTINCT 
    od.location, currentTires, currentAlignments, currentLubes, 
    currentBatteries,currentSiping,currentCarcount 
FROM 
    comm.dbo.ordetail as od 
LEFT JOIN 
    (SELECT 
     od2.location, SUM(od2.qty_shipped) as currentTires 
    FROM 
     comm.dbo.ordetail as od2 
    JOIN 
     comm.dbo.invmas as invmas2 ON invmas2.item_num = od2.item# 
    JOIN 
     comm.dbo.ordhrd as oh2 ON oh2.location = od2.location 
           AND oh2.inv_date = od2.inv_date 
           AND oh2.invoice# = od2.invoice# 
    WHERE 
     (oh2.type_of_rec = '01' OR oh2.type_of_rec = '02') 
     AND od2.inv_date >= '2017-02-01 00:00:00.000' 
     AND od2.inv_date <= '2017-02-28 00:00:00.000' 
     AND (invmas2.category = 'uhp' OR invmas2.category = 'tour' OR invmas2.category = 'mass' OR invmas2.category = 'suv' OR invmas2.category = 'ltat' OR invmas2.category = 'ltmt' OR invmas2.category = 'lthwy' OR invmas2.category = 'snow' OR invmas2.category = 'stdls') 
    GROUP BY 
     od2.location) as currentTires ON od.location = currentTires.location 
LEFT JOIN 
    (SELECT 
     od3.location, SUM(od3.qty_shipped) as currentAlignments 
    FROM 
     comm.dbo.ordetail as od3 
    JOIN 
     comm.dbo.invmas as invmas3 ON invmas3.item_num = od3.item# 
    JOIN 
     comm.dbo.ordhrd as oh3 ON oh3.location = od3.location 
           AND oh3.inv_date = od3.inv_date 
           AND oh3.invoice# = od3.invoice# 
    WHERE 
     (oh3.type_of_rec = '01' OR oh3.type_of_rec = '02') 
     AND od3.inv_date >= '2017-02-01 00:00:00.000' 
     AND od3.inv_date <= '2017-02-28 00:00:00.000' 
     AND (od3.item# = '8501' OR od3.item# = '8502') 
    GROUP BY 
     od3.location) as currentAlignments ON od.location = currentAlignments.location 
LEFT JOIN 
    (SELECT 
     od4.location, SUM(od4.qty_shipped) as currentLubes 
    FROM 
     comm.dbo.ordetail as od4 
    JOIN 
     comm.dbo.invmas as invmas4 ON invmas4.item_num = od4.item# 
    JOIN 
     comm.dbo.ordhrd as oh4 ON oh4.location = od4.location 
           AND oh4.inv_date = od4.inv_date 
           AND oh4.invoice# = od4.invoice# 
    WHERE 
     (oh4.type_of_rec = '01' OR oh4.type_of_rec = '02') 
     AND od4.inv_date >= '2017-02-01 00:00:00.000' 
     AND od4.inv_date <= '2017-02-28 00:00:00.000' 
     AND (od4.item# = '200fs' OR od4.item# = '200c' OR od4.item# = '200m' OR od4.item# = '200s') 
    GROUP BY 
     od4.location) as currentLubes ON od.location = currentLubes.location 
    LEFT JOIN (SELECT od5.location,SUM(od5.qty_shipped) as currentBatteries 
     FROM comm.dbo.ordetail as od5 
     JOIN comm.dbo.invmas as invmas5 
      ON invmas5.item_num = od5.item# 
     JOIN comm.dbo.ordhrd as oh5 
      ON oh5.location = od5.location 
      AND oh5.inv_date = od5.inv_date 
      AND oh5.invoice# = od5.invoice# 
     WHERE (oh5.type_of_rec = '01' OR oh5.type_of_rec = '02') 
      AND od5.inv_date >= '2017-02-01 00:00:00.000' 
      AND od5.inv_date <= '2017-02-28 00:00:00.000' 
      AND invmas5.manufact = 'inter' 
     GROUP BY od5.location) as currentBatteries 
     ON od.location = currentBatteries.location 
    LEFT JOIN (SELECT od6.location,SUM(od6.qty_shipped) as currentSiping 
     FROM comm.dbo.ordetail as od6 
     JOIN comm.dbo.invmas as invmas6 
      ON invmas6.item_num = od6.item# 
     JOIN comm.dbo.ordhrd as oh6 
      ON oh6.location = od6.location 
      AND oh6.inv_date = od6.inv_date 
      AND oh6.invoice# = od6.invoice# 
     WHERE (oh6.type_of_rec = '01' OR oh6.type_of_rec = '02') 
      AND od6.inv_date >= '2017-02-01 00:00:00.000' 
      AND od6.inv_date <= '2017-02-28 00:00:00.000' 
      AND invmas6.manufact = 'inter' 
     GROUP BY od6.location) as currentSiping 
     ON od.location = currentSiping.location 
    LEFT JOIN (SELECT od7.location,COUNT(DISTINCT oh7.invoice#) as currentCarcount 
     FROM comm.dbo.ordetail as od7 
     JOIN comm.dbo.ordhrd as oh7 
      ON oh7.location = od7.location 
      AND oh7.inv_date = od7.inv_date 
      AND oh7.invoice# = od7.invoice# 
     WHERE (oh7.type_of_rec = '01' OR oh7.type_of_rec = '02') 
      AND od7.inv_date >= '2017-02-01 00:00:00.000' 
      AND od7.inv_date <= '2017-02-28 00:00:00.000' 
      AND oh7.veh_make != '' 
      AND od7.item# != '' 
     GROUP BY od7.location) as currentCarcount 
     ON od.location = currentCarcount.location 
    ORDER BY od.location 

サンプル・データ出力:

enter image description here

+1

実行計画を確認しましたか? – user1413

+0

私はちょうど、私は私が見ているものに慣れていません。それを共有する簡単な方法ではありません。たくさんのデータ。 XML出力は5k行です。私は高コストの業務を特定し、それらを削減する方法を見つけるべきでしょうか? – Willee5586

+1

私はそれを意味しませんでした。 SSMSにはアイコンがあります。クエリメニュー - >見積もり実行計画を表示すると、表示された割合に基づいてより多くの時間を取ることができます。 – user1413

答えて

2

ここで良く作ることができるものがたくさんあります。まず、od5とod6の両方で同じ項目が返されるので、以下の結合の1つを取り除くことができます。

LEFT JOIN (SELECT od5.location,SUM(od5.qty_shipped) as currentBatteries 
    FROM comm.dbo.ordetail as od5 
    JOIN comm.dbo.invmas as invmas5 
     ON invmas5.item_num = od5.item# 
    JOIN comm.dbo.ordhrd as oh5 
     ON oh5.location = od5.location 
     AND oh5.inv_date = od5.inv_date 
     AND oh5.invoice# = od5.invoice# 
    WHERE (oh5.type_of_rec = '01' OR oh5.type_of_rec = '02') 
     AND od5.inv_date >= '2017-02-01 00:00:00.000' 
     AND od5.inv_date <= '2017-02-28 00:00:00.000' 
     AND invmas5.manufact = 'inter' 
    GROUP BY od5.location) as currentBatteries 
    ON od.location = currentBatteries.location 
LEFT JOIN (SELECT od6.location,SUM(od6.qty_shipped) as currentSiping 
    FROM comm.dbo.ordetail as od6 
    JOIN comm.dbo.invmas as invmas6 
     ON invmas6.item_num = od6.item# 
    JOIN comm.dbo.ordhrd as oh6 
     ON oh6.location = od6.location 
     AND oh6.inv_date = od6.inv_date 
     AND oh6.invoice# = od6.invoice# 
    WHERE (oh6.type_of_rec = '01' OR oh6.type_of_rec = '02') 
     AND od6.inv_date >= '2017-02-01 00:00:00.000' 
     AND od6.inv_date <= '2017-02-28 00:00:00.000' 
     AND invmas6.manufact = 'inter' 
    GROUP BY od6.location) as currentSiping 
    ON od.location = currentSiping.location 

パフォーマンスと可読性については、以下のように試してみてください。注:私はおそらくこれをテストすることはできませんが、パフォーマンスチューニングに時間を費やしてクエリをチューニングする人に洞察を与えるかもしれません。

DECLARE @LowDate DATETIME = '2017-02-01 00:00:00.000' 
DECLARE @HighDate DATETIME = '2017-02-28 00:00:00.000' 


SELECT 
    DetailList.location, 
    currentTires = SUM(currentTires), 
    currentAlignments = SUM(currentAlignments), 
    currentLubes = SUM(currentLubes), 
    currentBatteries = SUM(currentBatteries), 
    currentSiping = SUM(currentSiping),   
    carCount = SUM(hasCar) 
FROM 
(
    SELECT 
     od.location, 
     currentLubes=CASE WHEN (od.item# = '200fs' OR od.item# = '200c' OR od.item# = '200m' OR od.item# = '200s') THEN od.qty_shipped ELSE NULL END, 
     currentAlignments=CASE WHEN (od.item# = '8501' OR od.item# = '8502') THEN od.qty_shipped ELSE NULL END, 
     currentSiping = CASE WHEN (invmas.item_num = 'p15' OR invmas.item_num = 'u15') THEN od.qty_shipped ELSE NULL END, 
     currentBatteries = CASE WHEN invmas.manufact = 'inter' THEN od.qty_shipped ELSE NULL END, 
     currentTires= CASE WHEN (invmas.category = 'uhp' OR invmas.category = 'tour' OR invmas.category = 'mass' OR invmas.category = 'suv' OR invmas.category = 'ltat' OR 
        invmas.category = 'ltmt' OR invmas.category = 'lthwy' OR invmas.category = 'snow' OR invmas.category = 'stdls') THEN od.qty_shipped ELSE NULL END, 
    hasCar= CASE WHEN (oh.veh_make != '' AND od.item# !='') THEN 1 ELSE 0 END 
    FROM 
     comm.dbo.ordetail as od 
     LEFT JOIN comm.dbo.invmas as invmas ON invmas.item_num = od.item# --FOR currentCarcount 
     INNER JOIN comm.dbo.ordhrd as oh ON oh.location = od.location AND oh.inv_date = od.inv_date AND oh.invoice# = od.invoice# 
    WHERE 
     od.inv_date BETWEEN '2017-02-01 00:00:00.000' AND '2017-02-28 00:00:00.000' 
     AND 
     oh.type_of_rec IN('01','02') 
)AS DetailList 
GROUP BY 
    DetailList.location 
+0

私はそれを動作させるためにいくつかの変更を加えなければなりませんでした。同じだった2件の「ケース」は私の間違いだった。私はそれらを修正した。データセットは完了し、01秒の実行時間で実行されます。私に答えを提供するために時間をとってくれてありがとう。 – Willee5586

+0

うれしい私は助けることができます。 –

関連する問題