为什么在使用XQuery时存在Sort in执行计划

时间:2015-01-29 08:31:50

标签: sql-server performance sorting xquery sql-execution-plan

我在SQL Server中有一个包含10,000,000行的表

CREATE TABLE [dbo].[tmpTable](
    [EventId] [int] NULL,
    [Data] [nvarchar](max) NULL
) 
CREATE NONCLUSTERED INDEX [ci] ON [dbo].[tmpTable]
(
    [EventId] ASC
)
INCLUDE ([Data])

数据列是XML

当我使用SQL时,

    SELECT  EventId
  , CAST(Data AS xml ).value('(/d/nv/@v)[1]', 'uniqueidentifier') AS ID1
  , CAST(Data AS xml ).value('(/d/nv/@v)[2]', 'int') AS ID2
  , CAST(Data AS xml ).value('(/d/nv/@v)[3]', 'bigint') AS ID3
  , CAST(Data AS xml ).value('(/d/nv/@v)[4]', 'bit') AS ID4
  , CAST(Data AS xml ).value('(/d/nv/@v)[5]', 'nvarchar(100)') AS ID5
  , CAST(Data AS xml ).value('(/d/nv/@v)[6]', 'nvarchar(100)') AS ID6
  , CAST(Data AS xml ).value('(/d/nv/@v)[7]', 'bigint') AS ID7
  , CAST(Data AS xml ).value('(/d/nv/@v)[8]', 'int') AS ID8
    FROM tmpTable
    WHERE EventId = 100

执行计划中会有排序吗?这会扼杀性能。但是,如果我使用

Select Top 100

排序将消失。任何的想法?有没有办法删除排序

执行计划:

|--Compute Scalar(DEFINE:([Expr1011]=[Expr1010], [Expr1022]=[Expr1021], [Expr1033]=[Expr1032], [Expr1044]=[Expr1043], [Expr1055]=[Expr1054], [Expr1066]=[Expr1065], [Expr1077]=[Expr1076], [Expr1088]=[Expr1087]))
       |--Parallelism(Gather Streams)
            |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |    |    |    |    |    |--Sort(ORDER BY:([tmpTable].[dbo].[tmptmpTable].[Data] ASC))
                 |    |    |    |    |    |    |    |    |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([tmpTable].[dbo].[tmptmpTable].[Data]))
                 |    |    |    |    |    |    |    |         |--Table Scan(OBJECT:([tmpTable].[dbo].[tmptmpTable]), WHERE:([tmpTable].[dbo].[tmptmpTable].[EventId]=(100)))

示例数据

<d>
  <nv n="MediaDesc" v="79cc07e3-8d4a-4c8a-bc9f-3fcba485532b" />
  <nv n="ChannelNumber" v="116" />
  <nv n="Duration" v="61773" />
  <nv n="IsTunedToService" v="True" />
  <nv n="StreamSelection" v="FULLSCREEN_SECONDARY" />
  <nv n="ChannelType" v="LiveTVMediaChannel" />
  <nv n="TuneID" v="634050840267464082" />
</d>

2 个答案:

答案 0 :(得分:3)

如果将列的数据类型更改为XML而不是转换为XML,则会获得更好的性能。

转换为XML是一项昂贵的操作。 SQL Server尽最大努力尽快为您提供所需的结果,在这种情况下,它看起来像是使用表假脱机来完成工作。在您提供的计划中看不到假脱机,但我相信它在嵌套循环连接内的每个分支中都存在。

一些代码可以再现您所看到的内容。

create table T(S nvarchar(max) null);

go

insert into T(S) 
select top(50) '<N>1</N><N>2</N>'
from sys.columns;

insert into T(S) 
select top(50) '<N>3</N><N>4</N>'
from sys.columns;

您的查询:

select cast(T.S as xml).value('(N/text())[2]', 'int')
from T;

查询计划:

enter image description here

延迟假脱机缓存生成的最后一个结果集,只要外部部分的值相同,假脱机就可以返回缓存的结果集(倒带)。但是当当前输入值与先前的输入值不同时,假脱机必须生成新值的结果(重新绑定)。优化器添加了sort运算符以最小化重新绑定的数量。

您可以使用跟踪标记(8690)来删除使用排序和假脱机创建计划的优化。 Microsoft未对此进行记录,因此请勿在生产中使用它,但您可以在测试中使用它来查看优化对系统的影响。

select cast(T.S as xml).value('(N/text())[2]', 'int')
from T
option (querytraceon 8690);

有关Lazy Spool是什么以及如何工作的更多信息可以在this answer上找到,由Paul White在SQLPerformance.com上找到。

答案 1 :(得分:0)

看起来SORT与并行化有关。添加OPTION (MAXDOP 1)以防止并行处理。此外,如果EventId是唯一的,则使索引唯一。

编辑

表上没有聚集索引 - SORT可以连接到HEAP。使索引[ci]聚集。