bhs*_*bhs 2 performance sql-server execution-plan sql-server-2012 table-valued-parameters query-performance
我有一些运行缓慢的查询(按月分组的 100 万条记录中的 8 秒),并且一直试图理解执行计划。我们使用大约 10 个 TVP 来发送一组用户选择的过滤器,我有一个索引视图,占查询成本的 84%。
执行计划比较大,不能上传到这里,所以上传到这里了
我花了很多时间来尝试优化这些查询(其中有 14 个,但每个查询的核心都大同小异)并且希望任何人在阅读它们时提出建议或提示。我还实现了实际执行计划建议的查询,但查询速度慢了 5 倍?
wBo*_*Bob 11
我不认为这个查询是关于 TVP 的,而是关于复杂性的。该计划有一个优化器超时。您可以在 SELECT 运算符的 F4 属性中看到它作为“提前终止语句的原因 = 超时”或计划 xml 中的 StatementOptmEarlyAbortReason="TimeOut"。这些并不总是一场灾难,它只是意味着优化器已经用完了时间(更多的迭代)来提出一个计划并选择它在那个阶段成本最低的一个。优化器超时通常是查询过于复杂的标志,常见的建议是简化,例如分解它,删除不必要的参数和连接等
查看您的查询,有 13 个表。在计划中,他们中的许多人只是从查找表中执行“选择所有记录”(例如,来自 dbo.Station 的 @from 和 @to 表的所有记录,所有 ticketFilter 和 ticketClass 记录),所以实际上你没有需要这些表,删除它们不会改变结果。我知道这是一个用户驱动的查询,因此您可能会查看仅在用户实际应用过滤器时才加入表的方法。
我可以重现超时,并通过注释掉 4 个表来删除它,例如:
SELECT d.Month_Year[PeriodName], qg.Title [Service_Area], AVG((CAST(sa.Answer AS smallmoney) * 10.00)) [Average]
FROM [dbo].StaticDataView d WITH (NOEXPAND)
INNER JOIN [dbo].[Survey] s ON (s.CustomerJourney = d.Journey_Id)
INNER JOIN [dbo].[SurveyAnswer] sa ON (sa.Survey = s.ID)
INNER JOIN [dbo].[Question] q ON (q.ID = sa.Question)
INNER JOIN [dbo].[QuestionGroup] qg ON (qg.ID = q.QuestionGroupID)
--INNER JOIN @StationFrom sfl ON (sfl.ID = d.[Source])
--INNER JOIN @StationTo stl ON (stl.ID = d.[Dest])
INNER JOIN @InitialScores sc ON (s.Score = sc.ID)
INNER JOIN @RouteList rl ON (rl.ID = d.Route_ID) -- route list
--INNER JOIN @TicketClass tc ON (tc.ID = d.Class_ID)
--INNER JOIN @TicketTypeFilter ttl ON (ttl.ID = d.Ticket_Filter_Type_ID)
INNER JOIN @TicketDiscount td ON (td.ID = d.Discount_Type_ID)
INNER JOIN @Days dy ON (dy.ID = d.[DayOfWeek])
WHERE s.DateCompleted IS NOT NULL AND sa.Answer != -1
AND (d.RSID = COALESCE(@RSID, d.RSID))
AND (d.[Date] BETWEEN @Start AND @End) -- between dates
AND (d.[Time] BETWEEN @StartTime AND @EndTime) -- between times
AND ((@Direction IS NULL AND d.Direction IN (0,1)) -- Both
OR (@Direction = 1 AND d.Direction = 1) -- North
OR (@Direction = 0 AND d.Direction = 0)) -- South
AND ((@PassengerJourney = 0 AND d.Journey_Type_ID IN (1,2,3)) -- ALL
OR (@PassengerJourney IN (1,2) AND @PassengerJourney = d.Journey_Type_ID) -- Single or Return
OR (@PassengerJourney = 3 AND NULLIF(d.RSID_LEG_2,'') IS NOT NULL)) -- multi part
GROUP BY d.Month_Year, qg.Title
OPTION ( RECOMPILE )
Run Code Online (Sandbox Code Playgroud)
这是否有助于制定更好的计划?很难说,就像在我的简单装备中一样,无论有没有超时,我都无法在超过半秒的时间内运行此查询。甚至SQLFiddle似乎也没有挣扎。你能看出 SQLFiddle 重现和你的设置之间有多大区别吗?
| 归档时间: |
|
| 查看次数: |
315 次 |
| 最近记录: |