Rac*_*hel 14 performance sql-server-2005 stored-procedures query-performance
我有一个复杂的查询,它在查询窗口中运行 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
Run Code Online (Sandbox Code Playgroud)
最终结果如下所示:
日期 字母 代码 字母 已发送 已付金额 1/1/2012 1245 12345.67 2012 年 1 月 1 日 b 2301 1234.56 1/1/2012 c 1312 7894.45 2012 年 1 月 1 日 1455 2345.65 1/1/2012 c 3611 3213.21
我在确定速度下降的位置时遇到问题,因为在查询编辑器中一切都运行得非常快。只有当我将查询移动到存储过程时,它才开始运行很长时间。
我确定它与生成的查询执行计划有关,但我对 SQL 了解不足,无法确定可能导致问题的原因。
可能应该注意到,查询中使用的所有表都有数百万条记录。
有人可以向我解释为什么作为存储过程运行比在查询编辑器中运行的时间要长得多,并帮助我确定查询的哪一部分在作为存储过程运行时可能导致性能问题?
正如Martin 在评论中指出的那样,问题在于查询使用了不适合给定参数的缓存计划。
他在应用程序中慢,SSMS 中快速提供的链接?理解性能之谜提供了许多有用的信息,这些信息使我找到了一些解决方案。
我目前使用的解决方案是将参数复制到过程中的局部变量,我认为这会使 SQL 在运行时重新评估查询的执行计划,因此它为给定的参数选择最佳执行计划,而不是使用不适当的查询缓存计划。
其他可能有效的解决方案是使用OPTIMIZE FOR
或RECOMPILE
查询提示。