Tôi có một truy vấn phức tạp chạy trong 2 giây trong cửa sổ truy vấn, nhưng khoảng 5 phút dưới dạng Thủ tục được lưu trữ. Tại sao phải mất quá nhiều thời gian để chạy như một thủ tục được lưu trữ?
Đây là những gì truy vấn của tôi trông như thế nào.
Nó lấy một bộ hồ sơ cụ thể (được xác định bởi @id
và @createdDate
), và khung thời gian cụ thể (bắt đầu từ 1 năm @startDate
) và trả về một danh sách tóm tắt các thư được gửi và các khoản thanh toán ước tính nhận được do kết quả của các thư đó.
CREATE PROCEDURE MyStoredProcedure
@id int,
@createdDate varchar(20),
@startDate varchar(20)
AS
SET NOCOUNT ON
-- Get the number of records * .7
-- Only want to return records containing letters that were sent on 70% or more of the records
DECLARE @limit int
SET @limit = IsNull((SELECT Count(*) FROM RecordsTable WITH (NOLOCK) WHERE ForeignKeyId = @id AND Created = @createdDate), 0) * .07
SELECT DateSent as [Date]
, LetterCode as [Letter Code]
, Count(*) as [Letters Sent]
, SUM(CASE WHEN IsNull(P.DatePaid, '1/1/1753') BETWEEN DateSent AND DateAdd(day, 30, DateSent) THEN IsNull(P.TotalPaid, 0) ELSE 0 END) as [Amount Paid]
INTO #tmpTable
FROM (
-- Letters Table. Filter for specific letters
SELECT DateAdd(day, datediff(day, 0, LR.DateProcessed), 0) as [DateSent] -- Drop time from datetime
, LR.LetterCode -- Letter Id
, M.RecordId -- Record Id
FROM LetterRequest as LR WITH (NOLOCK)
INNER JOIN RecordsTable as M WITH (NOLOCK) ON LR.RecordId = M.RecordId
WHERE ForeignKeyId = @id AND Received = @createdDate
AND LR.Deleted = 0 AND IsNull(LR.ErrorDescription, '') = ''
AND LR.DateProcessed BETWEEN @startDate AND DateAdd(year, 1, @startDate)
AND LR.LetterCode IN ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o')
) as T
LEFT OUTER JOIN (
-- Payment Table. Payments that bounce are entered as a negative payment and are accounted for
SELECT PH.RecordId, PH.DatePaid, PH.TotalPaid
FROM PaymentHistory as PH WITH (NOLOCK)
INNER JOIN RecordsTable as M WITH (NOLOCK) ON PH.RecordId = M.RecordId
LEFT OUTER JOIN PaymentHistory as PR WITH (NOLOCK) ON PR.ReverseOfUId = PH.UID
WHERE PH.SomeString LIKE 'P_'
AND PR.UID is NULL
AND PH.DatePaid BETWEEN @startDate AND DateAdd(day, 30, DateAdd(year, 1, @startDate))
AND M.ForeignKeyId = @id AND M.Created = @createdDate
) as P ON T.RecordId = P.RecordId
GROUP BY DateSent, LetterCode
--HAVING Count(*) > @limit
ORDER BY DateSent, LetterCode
SELECT *
FROM #tmpTable
WHERE [Letters Sent] > @limit
DROP TABLE #tmpTable
Kết quả cuối cùng trông như thế này:
Mã thư ngày Thư đã gửi Số tiền phải trả 1/1/2012 a 1245 12345,67 1/1/2012 b 2301 1234.56 1/1/2012 c 1312 7894,45 1/1/2012 một 1455 2345,65 1/1/2012 c 3611 3213,21
Tôi đang gặp vấn đề khi tìm ra sự chậm lại ở đâu, bởi vì mọi thứ chạy rất nhanh trong trình soạn thảo truy vấn. Chỉ khi tôi di chuyển truy vấn đến một thủ tục được lưu trữ thì nó mới bắt đầu mất quá nhiều thời gian để chạy.
Tôi chắc chắn rằng nó có liên quan đến kế hoạch thực hiện truy vấn được tạo, nhưng tôi không biết đủ về SQL để xác định điều gì có thể gây ra sự cố.
Có lẽ cần lưu ý rằng tất cả các bảng được sử dụng trong truy vấn có hàng triệu bản ghi.
Ai đó có thể giải thích cho tôi tại sao việc này lại mất nhiều thời gian để chạy như một thủ tục được lưu trữ hơn trong trình soạn thảo truy vấn không và giúp tôi xác định phần nào trong truy vấn của tôi có thể gây ra sự cố về hiệu suất khi chạy như một thủ tục được lưu trữ?
RECOMPILE
gợi ý vì tôi không thực sự muốn biên dịch lại truy vấn mỗi khi nó chạy và bài viết bạn liên kết đã đề cập rằng sao chép tham số vào một biến cục bộ là tương đương với việc sử dụngOPTIMIZE FOR UNKNOWN
, dường như chỉ có sẵn trong 2008 và sau đó. Tôi nghĩ bây giờ tôi sẽ gắn bó với việc sao chép các tham số vào một biến cục bộ, điều này khiến thời gian thực hiện truy vấn của tôi giảm xuống còn 1-2 giây.