У мене складний запит, який працює за 2 секунди у вікні запиту, але приблизно 5 хвилин як збережена процедура. Чому запуск такої кількості часу триває як збережена процедура?
Ось як виглядає мій запит.
Він займає конкретний набір записів (ідентифікований @id
і @createdDate
) та конкретний часовий проміжок (1 рік, починаючи з @startDate
) і повертає узагальнений список відправлених листів та розрахункових платежів, отриманих у результаті цих листів.
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
Кінцевий результат виглядає приблизно так:
Код листів Літери, що надсилаються Сума сплачена 01.01.2012 р. 1245 12345.67 01.01.2012 р. 2301 1234.56 01.01.2012 c 1312 7894.45 01.01.2012 р. 1455 2345,65 01.01.2012 c 3611 3213.21
У мене виникають проблеми з розібранням, де знаходиться уповільнення, оскільки в редакторі запитів все працює надзвичайно швидко. Лише коли я переміщую запит на збережену процедуру, він починає так довго працювати.
Я впевнений, що це має щось спільне з генерацією плану виконання запитів, але я не знаю достатньо про SQL, щоб визначити, що може спричинити проблему.
Напевно, слід зазначити, що всі таблиці, використані в запиті, мають мільйони записів.
Чи може хтось пояснити мені, чому це забирає стільки часу, щоб запустити як збережену процедуру, ніж у редакторі запитів, і допоможе мені визначити, яка частина мого запиту може викликати проблеми з ефективністю при запуску як збережена процедура?
RECOMPILE
підказки, оскільки я не хочу перекомпілювати запит кожного разу, коли він запускається, а стаття, яку ви пов’язали, згадала, що параметри копіювання на локальну змінну еквівалентні використаннюOPTIMIZE FOR UNKNOWN
, яке, здається, доступне лише в 2008 р. І пізніше. Я думаю, що зараз я буду дотримуватися копіювання параметрів до локальної змінної, що приводить час мого виконання запитів до 1-2 секунд.