Sql server SQL Server XML列性能
将包含XML的nText列转换为XML数据类型会导致SQL Server中的性能下降 我目前正在从事一个项目,其中使用了nText列来存储有效的XML。我已经成功地将这些列迁移到XML数据类型。然而,根据SQLProfiler,XML数据类型的性能比使用nText或nvarchar(max)存储XML要差。我所读到的一切都暗示,情况不应该如此 为了验证这一点,我创建了两个具有相同索引的表等Sql server SQL Server XML列性能,sql-server,xml,performance,tsql,xquery,Sql Server,Xml,Performance,Tsql,Xquery,将包含XML的nText列转换为XML数据类型会导致SQL Server中的性能下降 我目前正在从事一个项目,其中使用了nText列来存储有效的XML。我已经成功地将这些列迁移到XML数据类型。然而,根据SQLProfiler,XML数据类型的性能比使用nText或nvarchar(max)存储XML要差。我所读到的一切都暗示,情况不应该如此 为了验证这一点,我创建了两个具有相同索引的表等 Table Name Order1 [id] [int] IDENTITY(1,1) NOT NULL,
Table Name Order1
[id] [int] IDENTITY(1,1) NOT NULL,
[uid] [varchar](36) NOT NULL,
[AffiliateId] [varchar](36) NOT NULL,
[Address] [ntext] NOT NULL,
[CustomProperties] [ntext] NOT NULL,
[OrderNumber] [nvarchar](50) NOT NULL,
...
Table Name Order2
[id] [int] IDENTITY(1,1) NOT NULL,
[uid] [varchar](36) NOT NULL,
[AffiliateId] [varchar](36) NOT NULL,
[Address] [xml] NOT NULL,
[CustomProperties] [xml] NOT NULL,
[OrderNumber] [nvarchar](50) NOT NULL,
...
然后,我使用select/insert语句复制了数据,并在两个表上重建了索引。然后,我使用以下SQL创建了一个脚本
DBCC DROPCLEANBUFFERS
GO
--Part1
Select id, uid, AffiliateId, Address, CustomProperties, OrderNumber from [dbo].[Order1] where uid = 'F96045F8-A2BD-4C02-BECB-6EF22C9E473F'
Select id, uid, AffiliateId, Address, CustomProperties, OrderNumber from [dbo].[Order1] where uid = 'A3B71348-EB68-4600-9550-EC2CF75698F4'
Select id, uid, AffiliateId, Address, CustomProperties, OrderNumber from [dbo].[Order1] where uid = 'CB114D91-F000-4553-8AFE-FC20CF6AD8C0'
Select id, uid, AffiliateId, Address, CustomProperties, OrderNumber from [dbo].[Order1] where uid = '06274E4F-E233-4594-B505-D4BAA3770F0A'
DBCC DROPCLEANBUFFERS
GO
--Part2
Select id, uid, AffiliateId, Address, OrderNumber,
CAST(CustomProperties AS xml).query('CustomProperty/Key[text()="AgreedToTerms"]/../Value/text()') as "TermsAgreed"
from Order1
DBCC DROPCLEANBUFFERS
GO
--Part3
Insert Into Order1 uid, AffiliateId, Address, CustomProperties, OrderNumber
Select NewId(), AffiliateId, Address, CustomProperties, OrderNumber + 'X' from [dbo].[Order1] where uid = 'F96045F8-A2BD-4C02-BECB-6EF22C9E473F'
Insert Into Order1 uid, AffiliateId, Address, CustomProperties, OrderNumber
Select NewId(), AffiliateId, Address, CustomProperties, OrderNumber + 'X' from [dbo].[Order1] where uid = 'A3B71348-EB68-4600-9550-EC2CF75698F4'
Insert Into Order1 uid, AffiliateId, Address, CustomProperties, OrderNumber
Select NewId(), AffiliateId, Address, CustomProperties, OrderNumber + 'X' from [dbo].[Order1] where uid = 'CB114D91-F000-4553-8AFE-FC20CF6AD8C0'
Insert Into Order1 uid, AffiliateId, Address, CustomProperties, OrderNumber
Select NewId(), AffiliateId, Address, CustomProperties, OrderNumber + 'X' from [dbo].[Order1] where uid = '06274E4F-E233-4594-B505-D4BAA3770F0A'
DBCC DROPCLEANBUFFERS
GO
-- Part4 This updates a .5M row table.
Update [dbo].[Order1] Set CustomProperties = Cast(CustomProperties as NVARCHAR(MAX)) + CAST('' as NVARCHAR(MAX)), Address = Cast(CustomProperties as NVARCHAR(MAX)) + CAST('' as NVARCHAR(MAX))
SQL事件探查器的平均结果如下所示:-
NTEXT
+-------+-------------+-------------+-------------+-------------+
| Test | CPU | Reads | Writes | Duration |
+-------+-------------+-------------+-------------+-------------+
| Part1 | 281.3333333 | 129.3333333 | 0 | 933 |
| Part2 | 78421.66667 | 5374306 | 10.66666667 | 47493.66667 |
| Part3 | 281.6666667 | 616 | 27.66666667 | 374.6666667 |
| Part4 | 40312.33333 | 15311252.67 | 320662 | 67010 |
| Total | | | | 115811.3333 |
+-------+-------------+-------------+-------------+-------------+
XML
+-------+-------------+-------------+-------------+-------------+
| Test | CPU | Reads | Writes | Duration |
+-------+-------------+-------------+-------------+-------------+
| Part1 | 282 | 58.33333333 | 0 | 949.3333333 |
| Part2 | 21129.66667 | 180143.3333 | 0 | 76048.66667 |
| Part3 | 297 | 370.3333333 | 14.66666667 | 378 |
| Part4 | 112578.3333 | 8908940.667 | 145703.6667 | 114684.3333 |
| Total | | | | 192060.3333 |
+-------+-------------+-------------+-------------+-------------+
测试脚本有缺陷吗?或者,是否需要对xml数据类型列进行其他优化
我希望XML列类型的性能优于ntext。所以这可能不是一个答案,至少不是一个解决方案,但希望它能帮助理解正在发生的事情 XML最昂贵的部分是初始解析,换句话说:文本表示和技术存储之间的转换 重要的是要知道:原生XML不是作为您看到的文本存储的,而是作为层次表存储的。当您将一些文本XML传递到SQL Server时,这需要非常繁重的处理。为人类读者调用此XML需要相反的过程。将此字符串存储在字符串列中(请注意,
NTEXT
几个世纪以来一直被弃用)比将其存储为原生XML要快,但会失去许多优势
因此,对于您的脚本:
我假设您运行了相同的脚本,但只是将Order1
更改为Order2
。这是正确的吗
第1部分测量一个简单的SELECT
。
为了提供可读的表示,SQLServer(或者更确切地说是SSMS)将把任何值转换为某种文本。如果您的表包含int、guid或DateTime,您将看不到实际的位模式,是吗?SSM将使用非常昂贵的操作为您创建可读的内容。代价高昂的部分是转型。字符串不需要这个,所以NTEXT会更快
第2部分度量了.query()
方法(还涉及“如何显示结果”)。
您是否也将CAST(作为XML)
与Order2
一起使用?然而,有了这样的需求,XML应该会更快,因为NTEXT将不得不反复进行繁重的解析,而XML已经以可查询的格式存储。。。但是您的XQuery是次优的(由于向后导航。/Value
)。试试这个:
.query('/CustomProperty[Key[text()="AgreedToTerms"]]/Value/text()')
这将查找具有给定内容的
的
,并将阅读
下面的
,而无需。/
我当然希望XML在这里的转换比NTEXT更好。。。对全新表和索引的第一次调用可能会返回有偏差的结果
第3部分措施插入
在这里,我希望能有同样的表现。。。如果您将一个字符串值移动到另一个字符串列中,这就是简单的复制。将本机XML移动到另一个XML列也很简单
第4部分措施更新
这看起来很奇怪。。。你想达到什么目标?代码需要将本机XML转换为字符串,并重新解析它们以存储在XML中。对NTEXT执行同样的操作根本不需要这些昂贵的操作
一些普遍的想法
插入
,停止时钟并按下临时表的输出)使用master;
去
创建数据库testShnugo;
去
使用testShnugo;
去
创建表dbo.with字符串(ID INT,SomeXML NTEXT);
创建表dbo.WithXML(ID INT,SomeXML);
去
--在两个表中插入100.000行
将计数(Nmbr)设置为(从主控..spt_值v1交叉连接主控..spt_值v2)中选择(ORDER BY(SELECT NULL))上方的前100000行编号()
插入dbo.WithXML(ID,SomeXML)
选择Nmbr,(选择Nmbr作为[@Nmbr],选择CONCAT('hallo',Nmbr)作为[SomeTest/@FindMe],选择CONCAT('SomeTestValue',Nmbr)作为[SomeTest],用于XML路径('row')、根('ROOT')、类型)
从理货
--将所有内容复制到第二个表中
使用字符串(ID,SomeXML)从dbo.WithXML中选择ID,CAST(SomeXML作为NVARCHAR(MAX));
去
--检查实际内容
从dbo.WithString中选择*;
从dbo.WithXML中选择*;
去
声明@d DATETIME2=SYSUTCDATETIME();
从dbo.with字符串中选择*,其中包含一些XML,如“%FindMe=”hallo333“%”
打印“类似字符串方法”
打印日期差(毫秒,@d,SYSUTCDATETIME());
设置@d=SYSUTCDATETIME();
选择*FROM dbo.WithString WHERE CAST(SomeXML作为xml)。exist('/root/row[SomeTest[@FindMe=“hallo333”]')=1
打印“将NTEXT转换为XML和.exist()”
打印日期差(毫秒,@d,SYSUTCDATETIME());
设置@d=SYSUTCDATETIME();
选择*FROM dbo.WithXML WHERE CAST(SomeXML作为nvarchar(MAX)),如“%FindMe=”hallo333“%”
打印“将XML转换为NVARCHAR(MAX)后的字符串方法”
打印日期差(毫秒,@d,SYSUTCDATETIME());
设置@d=SYSUTCDATETIME();
选择*FROM dbo.WithXML,其中SomeXML.exist('/root/row[SomeTest[@FindMe=“hallo333”]]')=1
打印“带.exist()的本机XML”
打印日期差(毫秒,@d,SYSUTCDATETIME());
去
使用master;
去
删除数据库testShnugo;
<root>
<row nmbr="1">
<SomeTest FindMe="hallo1">SomeTestValue1</SomeTest>
</row>
</root>
String-Method LIKE
836
CAST NTEXT to XML and .exist()
1962
String-Method LIKE after CAST XML to NVARCHAR(MAX)
1079
native XML with .exist()
911
SELECT Nmbr,(SELECT TOP 100 Nmbr AS [@nmbr],CONCAT('hallo',x.Nmbr) AS [SomeTest/@FindMe],CONCAT('SomeTestValue',x.Nmbr) As [SomeTest] FROM Tally x FOR XML PATH('row'),ROOT('root'),TYPE)
<root>
<row nmbr="1">
<SomeTest FindMe="hallo1">SomeTestValue1</SomeTest>
</row>
<row nmbr="2">
<SomeTest FindMe="hallo2">SomeTestValue2</SomeTest>
</row>
<row nmbr="3">
<SomeTest FindMe="hallo3">SomeTestValue3</SomeTest>
</row>
...more of them
String-Method LIKE
71959
CAST NTEXT to XML and .exist()
74773
String-Method LIKE after CAST XML to NVARCHAR(MAX)
104380
native XML with .exist()
16374