申し分なく、私は信じられないほど遅く実行していたレポートストアドプロシージャを持っています。レポートが実行されないという顧客からの不満があったため、ストアドプロシージャのどこに問題があるのかを正確に調査し始め、この部分が時間の99.8%を占めることがわかりました。
DECLARE @xmlTemp TABLE (
CompanyID INT,
StoreID INT,
StartDate DATETIME,
DateStaID INT,
EndDate DATETIME,
DateEndID INT,
LastUpdate DATETIME)
INSERT INTO @xmlTemp
VALUES (50,
2,
'3/3/2013',
0,
'3/3/2013',
0,
'3/3/2013')
SELECT DISTINCT T.CompanyID,
CompanyName,
Z.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut,
Total - Isnull((SELECT Sum(DISTINCT PaymentAmount)
FROM vPullDrawerPayments
WHERE CompanyID = T.CompanyID
AND StoreID = T.StoreID
AND TransactionID = T.TransactionID
AND Isnull(PaymentType, 1) <> 1), 0) AS PaymentAmount,
'Cash' AS PaymentDesc,
CASE
WHEN Z.EndDate >= Z.LastUpdate THEN 1
ELSE 0
END AS MissingData
FROM vPullDrawerPayments AS T
INNER JOIN @xmlTemp AS Z
ON T.CompanyID = Z.CompanyID
AND T.StoreID = Z.StoreID
WHERE BusinessDate BETWEEN Z.StartDate AND Z.EndDate
UNION ALL
SELECT DISTINCT NC.CompanyID,
CompanyName,
Z.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut,
PaymentAmount,
PaymentDesc,
CASE
WHEN Z.EndDate >= Z.LastUpdate THEN 1
ELSE 0
END AS MissingData
FROM vPullDrawerPayments AS NC
INNER JOIN @xmlTemp AS Z
ON NC.CompanyID = Z.CompanyID
AND NC.StoreID = Z.StoreID
WHERE BusinessDate BETWEEN Z.StartDate AND Z.EndDate
AND Isnull(PaymentType, 1) <> 1
UNION ALL
SELECT DISTINCT C.CompanyID,
CompanyName,
Z.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut,
Sum(Abs(LineAmount)) AS PaymentAmount,
'Coupons' AS PaymentDesc,
CASE
WHEN Max(Z.EndDate) >= Max(Z.LastUpdate) THEN 1
ELSE 0
END AS MissingData
FROM vPullDrawerPayments AS C
INNER JOIN @xmlTemp AS Z
ON C.CompanyID = Z.CompanyID
AND C.StoreID = Z.StoreID
WHERE BusinessDate BETWEEN Z.StartDate AND Z.EndDate
GROUP BY C.CompanyID,
CompanyName,
Z.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut
このクエリの@xmlTemp部分は、通常、Webアプリケーションからパラメーターを取得して、レポートで実際に使用できるパラメーターに変換するために使用されます。これをテストするために、これを1つのストアに対して1日に実行する値を挿入しています。この部分の実行には、20分以上かかる場合があります。
したがって、このクエリプランを PlanExplorer で実行したところ、そのストアとその日だけを除外するのではなく、2つのファクトテーブルからすべてのデータを取得していることがわかりました。下の写真のように。
これは明らかに悪いことです。したがって、私が取った次のステップは、@ xml tempの結合を切り取り、クエリのWHERE
句に値を手動で入力して、どのように機能するかを確認することです。
SELECT DISTINCT T.CompanyID,
CompanyName,
T.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut,
Total - Isnull((SELECT Sum(DISTINCT PaymentAmount)
FROM vPullDrawerPayments
WHERE CompanyID = T.CompanyID
AND StoreID = T.StoreID
AND TransactionID = T.TransactionID
AND Isnull(PaymentType, 1) <> 1), 0) AS PaymentAmount,
'Cash' AS PaymentDesc
--CASE WHEN Z.'3/3/2013' >= Z.LastUpdate THEN 1 ELSE 0 END AS MissingData
FROM vPullDrawerPayments AS T
WHERE CompanyID = 50
AND StoreID = 1
AND BusinessDate BETWEEN '3/3/2013' AND '3/3/2013'
UNION ALL
SELECT DISTINCT NC.CompanyID,
CompanyName,
NC.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut,
PaymentAmount,
PaymentDesc
--CASE WHEN Z.'3/3/2013' >= Z.LastUpdate THEN 1 ELSE 0 END AS MissingData
FROM vPullDrawerPayments AS NC
WHERE CompanyID = 50
AND StoreID = 1
AND BusinessDate BETWEEN '3/3/2013' AND '3/3/2013'
AND Isnull(PaymentType, 1) <> 1
UNION ALL
SELECT DISTINCT C.CompanyID,
CompanyName,
C.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut,
Sum(Abs(LineAmount)) AS PaymentAmount,
'Coupons' AS PaymentDesc
--CASE WHEN MAX(Z.'3/3/2013') >= MAX(Z.LastUpdate) THEN 1 ELSE 0 END AS MissingData
FROM vPullDrawerPayments AS C
WHERE CompanyID = 50
AND StoreID = 1
AND BusinessDate BETWEEN '3/3/2013' AND '3/3/2013'
GROUP BY C.CompanyID,
CompanyName,
C.StoreID,
StoreName,
CashedOutBy,
TransactionID,
RegisterID,
BusinessDate,
CashedOut
これを単純なwhere句に変更すると、20分以上ではなく4秒で実行されます。また、クエリプランは正しいことを示しています。この動作が表示されるはずの理由はありますか?
ここでの編集は QueryPlan への完全なリンクです。
[コピー SQLPerformance.comでの私の答え 。]
他の場所での議論からのいくつかの非常に短い最初の提案: