She*_*115 6 performance sql-server execution-plan view sql-server-2016 query-performance
执行计划作为查询
SELECT VP.Branch
, VP.ROUTE AS Route
, VP.SAPCustomerID
, S.CustomerID
, S.ProductID
, S.Date
-- Group by Customer
, CustomerQuantity = SUM(S.Quantity) OVER (PARTITION BY VP.Branch, VP.ROUTE, VP.SAPCustomerID, S.ProductID, S.Date)
, CustomerFourWeekSalesAvg = SUM(S.FourWeekSalesAvg) OVER (PARTITION BY VP.Branch, VP.ROUTE, VP.SAPCustomerID, S.ProductID, S.Date)
-- Group by Route
, SUM(S.Quantity) OVER (PARTITION BY VP.Branch, VP.ROUTE, S.ProductID, S.Date) AS RouteQuantity
, RouteFourWeekSalesAvg = SUM(S.FourWeekSalesAvg) OVER (PARTITION BY VP.Branch, VP.ROUTE, S.ProductID, S.Date)
-- Group by Branch
, BranchQuantity = SUM(S.Quantity) OVER (PARTITION BY VP.Branch, S.ProductID, S.Date)
, BranchFourWeekSalesAvg = SUM(S.FourWeekSalesAvg) OVER (PARTITION BY VP.Branch, S.ProductID, S.Date)
FROM vw_SalesByWeek AS S
INNER JOIN SAP_VisitPlan AS VP WITH (NOLOCK)
ON VP.CustomerID = S.CustomerID
AND VP.DateFrom <= S.Date
AND VP.DateTo >= S.Date
Run Code Online (Sandbox Code Playgroud)
执行计划作为视图
-- Where vw_SalesByWeekSummary is the query above exactly.
SELECT [Branch]
,[Route]
,[SAPCustomerID]
,[CustomerID]
,[ProductID]
,[Date]
,[CustomerQuantity]
,[CustomerFourWeekSalesAvg]
,[RouteQuantity]
,[RouteFourWeekSalesAvg]
,[BranchQuantity]
,[BranchFourWeekSalesAvg]
FROM vw_SalesByWeekSummary
WHERE Route = '0600'
Run Code Online (Sandbox Code Playgroud)
问题
查询单独或作为存储过程工作得很好;但是,作为视图的查询决定进行扫描而不是查找并使用不同的索引。如何让查询作为视图正常运行?是什么导致它使用不同的索引和扫描而不是搜索?
SQL计划文件
索引
-- Solo Query Plan Indexes
CREATE NONCLUSTERED INDEX [IX_VisitPlan_ByRoute] ON [dbo].[SAP_VisitPlan] ([ROUTE] ASC) INCLUDE ([Branch])
CREATE UNIQUE NONCLUSTERED INDEX [UIX_CacheCS_ByWeek] ON [dbo].[Cache_ConvSalesByWeek] ([CustomerID] ASC, [ProductID] ASC, [WkStartDate] ASC) INCLUDE ([ID], [SoldQuantity], [Route], [FourWeekSalesAvg], [NumberOfPriorSalesWeeks])
CREATE NONCLUSTERED INDEX [IX_CacheSS_4wkAvg] ON [dbo].[Cache_ScanSalesByWeek] ([CustomerID] ASC, [ProductID] ASC, [Route] ASC) INCLUDE ([FourWeekSalesAvg], [WkStartDate], [SoldQuantity])
-- View Query Plan Indexes
CREATE UNIQUE NONCLUSTERED INDEX [UIX_VisitPlan_PK] ON [dbo].[SAP_VisitPlan] ([SAPCustomerID] ASC, [CustomerID] ASC, [DateTo] DESC, [DateFrom] DESC, [ROUTE] ASC, [DriverNumber] ASC) INCLUDE ([Branch])
CREATE NONCLUSTERED INDEX [IX_CacheCS] ON [dbo].[Cache_ConvSalesByWeek] ([CustomerID] ASC, [ProductID] ASC, [WkStartDate] ASC) INCLUDE ([SoldQuantity], [FourWeekSalesAvg], [Route])
CREATE NONCLUSTERED INDEX [IX_ScanSalesByWeek_Sunday] ON [dbo].[Cache_ScanSalesByWeek] ([WkStartDate] ASC) INCLUDE ([CustomerID], [ProductID], [SoldQuantity], [Route], [FourWeekSalesAvg])
Run Code Online (Sandbox Code Playgroud)
Pau*_*ite 11
基本问题是Route = N'0600' 在计算窗口函数之前过滤(如在查询中)与Route = N'0600' 在计算窗口函数之后过滤(如在视图中)不同。
这通常会为窗口函数提供不同(= 不正确)的结果,因此优化器不会这样做。有关更多信息,请参阅Erik Darling 的Of Windowing Functions And Where Clauses。
如果视图中的所有窗口函数都在 上进行分区Route,优化器会考虑将谓词下推到视图中,因为仍然会获得正确的结果。遗憾的是,您的观点并非如此。OPTION (RECOMPILE)在这种情况下,添加无济于事。
考虑将视图重写(或补充)为内联表值函数,并为Route. 我在 Stack Overflow 上的回答中有一个该技术的例子。
如果您有其他过滤条件Route,并且无论如何您都将拥有一个存储过程,您可以抽象出过滤条件的类型 - 为路由创建一个 TVF,当路由传递给存储过程时,调用它. 为日期范围制作另一个 TVF,当日期过去时,调用它。当它们同时传递路由和日期时会变得复杂(如果可能的话),但无论传递哪个参数,分离都可能是获得可靠可预测性能的最安全方法。如果您有可选的过滤条件,那么动态 SQL 和/或选项(重新编译)可能是您最好的选择。
| 归档时间: |
|
| 查看次数: |
178 次 |
| 最近记录: |