避免在没有ORDER BY关键字的更新查询的索引计划中排序运算符

时间:2017-09-21 10:33:59

标签: tsql indexing sql-server-2012 sqlperformance query-planner

我有更新查询: -

Update PM.Contractual_Allowances  Set Provider_ID = 3  Where Tenant_ID = 1 and Carrier_ID = 203

对于上面这个查询,我得到的执行计划如下:

Execution Plan

我试图理解为什么当我没有ORDER BY子句时我会得到sort运算符以及我可以做些什么来避免它。

以下是文字计划(又名' Showplan_text'):

|--Sequence
   |--Index Update(OBJECT:([Ntier_Master].[PM].[Contractual_Allowances].[IX_Contractual_Allowances_Provider_ID_Tenant_ID]), SET:([Contractual_Allowance_ID1043] = [Ntier_Master].[PM].[Contractual_Allowances].[Contractual_Allowance_ID],[Provider_ID1044] = [Ntier_Master].[PM].[Contractual_Allowances].[Provider_ID],[Tenant_ID1045] = [Ntier_Master].[PM].[Contractual_Allowances].[Tenant_ID]) WITH ORDERED PREFETCH ACTION:([Act1042]))
   |    |--Sort(ORDER BY:([Ntier_Master].[PM].[Contractual_Allowances].[Provider_ID] ASC, [Ntier_Master].[PM].[Contractual_Allowances].[Tenant_ID] ASC, [Ntier_Master].[PM].[Contractual_Allowances].[Contractual_Allowance_ID] ASC, [Act1042] ASC))
   |         |--Filter(WHERE:(NOT [Expr1038]))
   |              |--Table Spool
   |                   |--Split
   |                        |--Clustered Index Update(OBJECT:([Ntier_Master].[PM].[Contractual_Allowances].[PK_Contractual_Allowances_Contractual_Allowance_ID]), SET:([Ntier_Master].[PM].[Contractual_Allowances].[Provider_ID] = [Expr1033],[Ntier_Master].[PM].[Contractual_Allowances].[Contractual_Allowance_TS] = [Expr1003]))
   |                             |--Compute Scalar(DEFINE:([Expr1038]=[Expr1038], [Expr1039]=[Expr1039]))
   |                                  |--Compute Scalar(DEFINE:([Expr1038]=CASE WHEN [Expr1007] THEN (1) ELSE (0) END, [Expr1039]=CASE WHEN [Expr1007] THEN (1) ELSE (0) END))
   |                                       |--Compute Scalar(DEFINE:([Expr1033]=(3)))
   |                                            |--Compute Scalar(DEFINE:([Expr1007]=CASE WHEN [Ntier_Master].[PM].[Contractual_Allowances].[Provider_ID] = (3) THEN (1) ELSE (0) END))
   |                                                 |--Compute Scalar(DEFINE:([Expr1003]=gettimestamp((10))))
   |                                                      |--Clustered Index Scan(OBJECT:([Ntier_Master].[PM].[Contractual_Allowances].[PK_Contractual_Allowances_Contractual_Allowance_ID]),  WHERE:([Ntier_Master].[PM].[Contractual_Allowances].[Tenant_ID]=(1) AND [Ntier_Master].[PM].[Contractual_Allowances].[Carrier_ID]=(203)) ORDERED FORWARD)
   |--Index Update(OBJECT:([Ntier_Master].[PM].[Contractual_Allowances].[IX_Contractual_Allowances_Carrier_ID_Location_ID_Department_ID_Tenant_ID]), SET:([Contractual_Allowance_ID1046] = [Ntier_Master].[PM].[Contractual_Allowances].[Contractual_Allowance_ID],[Modifiers1047] = [Ntier_Master].[PM].[Contractual_Allowances].[Modifiers],[Carrier_ID1048] = [Ntier_Master].[PM].[Contractual_Allowances].[Carrier_ID],[Procedure_Code_ID1049] = [Ntier_Master].[PM].[Contractual_Allowances].[Procedure_Code_ID],[Location_ID1050] = [Ntier_Master].[PM].[Contractual_Allowances].[Location_ID],[Provider_ID1051] = [Ntier_Master].[PM].[Contractual_Allowances].[Provider_ID],[Department_ID1052] = [Ntier_Master].[PM].[Contractual_Allowances].[Department_ID],[Tenant_ID1053] = [Ntier_Master].[PM].[Contractual_Allowances].[Tenant_ID]) WITH ORDERED PREFETCH ACTION:([Act1042]))
        |--Sort(ORDER BY:([Ntier_Master].[PM].[Contractual_Allowances].[Carrier_ID] ASC, [Ntier_Master].[PM].[Contractual_Allowances].[Location_ID] ASC, [Ntier_Master].[PM].[Contractual_Allowances].[Department_ID] ASC, [Ntier_Master].[PM].[Contractual_Allowances].[Tenant_ID] ASC, [Ntier_Master].[PM].[Contractual_Allowances].[Contractual_Allowance_ID] ASC, [Act1042] ASC))
             |--Filter(WHERE:(NOT [Expr1039]))
                  |--Table Spool




 CREATE NONCLUSTERED INDEX IX_Contractual_Allowances_Location_ID_Tenant_ID ON PM.Contractual_Allowances (  Location_ID ASC  , Tenant_ID ASC  )   WITH (  PAD_INDEX =  OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [PRIMARY ] 
 CREATE NONCLUSTERED INDEX IX_Contractual_Allowances_Provider_ID_Tenant_ID ON PM.Contractual_Allowances (  Provider_ID ASC  , Tenant_ID ASC  )   WITH (  PAD_INDEX =  OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [PRIMARY ] 
 CREATE NONCLUSTERED INDEX IX_Contractual_Allowances_Carrier_ID_Current_Effective_Date_Tenant_ID ON PM.Contractual_Allowances (  Carrier_ID ASC  , Current_Effective_Date ASC  , Tenant_ID ASC  )   WITH (  PAD_INDEX =  OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [PRIMARY ] 
 CREATE NONCLUSTERED INDEX IX_Contractual_Allowances_Carrier_ID_Location_ID_Department_ID_Tenant_ID ON PM.Contractual_Allowances (  Carrier_ID ASC  , Location_ID ASC  , Department_ID ASC  , Tenant_ID ASC  )   INCLUDE ( Modifiers , Procedure_Code_ID , Provider_ID )  WITH (  PAD_INDEX =  OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [PRIMARY ] 
CREATE NONCLUSTERED INDEX IX_Contractual_Allowances_Procedure_Code_ID_Tenant_ID ON PM.Contractual_Allowances (  Procedure_Code_ID ASC  , Tenant_ID ASC  )   WITH (  PAD_INDEX =  OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [PRIMARY ] 

1 个答案:

答案 0 :(得分:2)

ORDER BY子句不是导致排序的唯一因素。 GROUP BY,DISTINCT,窗口排名函数(例如ROW_NUMBER,RANK),窗口聚合函数(例如SUM()OVER(PARTITION BY ...),窗口框架函数(例如LAG和LEAD)是导致排序的许多因素。

当我们添加索引时,我们会对数据进行预排序,以便在查询时不需要对其进行排序。 exectution计划中的排序意味着(1)没有可用于处理排序的索引或(2)是可以处理排序但是优化器选择不使用它的索引。请考虑以下示例数据:

if object_id('tempdb..#sometable') is not null drop table #sometable;
create table #sometable (col1 int, col2 int);
insert #sometable values(1,10),(1,20),(2,15),(2,50),(3,10);

接下来,使用"包含实际执行计划"运行这些查询。打开了。

select col1, max(col2)
from #sometable
group by col1;

select distinct col1
from #sometable;

select col1, col2, avg(col2) over (partition by col1)
from #sometable;

select col1, col2, avg(col2) over (partition by col1 order by (select null))
from #sometable;

请注意执行计划:

enter image description here

您可以通过将鼠标悬停在排序运算符上来获取有关排序内容的更多信息:

enter image description here

这里需要对col1进行排序,所以让我们添加这个索引,运行查询并检查执行计划:

--alter table #sometable
create clustered index uq_sometable on #sometable(col1);

现在新的执行计划:

enter image description here

正如你所看到的,各种各样都消失了。对于这个主题还有更多的内容,但希望这有助于您了解如何在没有ORDER BY的情况下获得排序以及如何摆脱它们。