SQL 2005和SQL 2008在使用XML插入多行方面的差异
可能重复:SQL 2005和SQL 2008在使用XML插入多行方面的差异,xml,sql-server-2005,sql-server-2008,Xml,Sql Server 2005,Sql Server 2008,可能重复: 我使用以下SQL代码在表中插入多行数据。使用XML变量将数据传递到存储过程: INSERT INTO MyTable SELECT SampleTime = T.Item.value('SampleTime[1]', 'datetime'), Volume1 = T.Item.value('Volume1[1]', 'float'), Volume2 = T.Item.value('Volume2[1]', 'float') FR
我使用以下SQL代码在表中插入多行数据。使用XML变量将数据传递到存储过程:
INSERT INTO MyTable
SELECT SampleTime = T.Item.value('SampleTime[1]', 'datetime'),
Volume1 = T.Item.value('Volume1[1]', 'float'),
Volume2 = T.Item.value('Volume2[1]', 'float')
FROM @xml.nodes('//Root/MyRecord') T(item)
我有一大堆的单元测试来验证我是否插入了正确的信息、正确的记录数等等。。当我调用存储过程时
一切都很好,也就是说,直到我们开始胡闹数据库的兼容性级别
只要我们将DB的兼容性级别保持在90(SQL 2005),上面的代码就工作得很好。
当我们将兼容性级别设置为100(SQL 2008)时,单元测试失败,因为使用上述代码的存储过程超时
单元测试正在删除数据库,从脚本重新创建数据库,并在全新的数据库上运行测试,因此我认为这不是“旧的兼容性级别”的问题
使用SQLManagementStudio,我编写了一个快速测试SQL脚本。使用相同的XML块,我改变DB compat级别,截断表,然后使用上面的代码插入650行。当级别为90(SQL 2005)时,它以毫秒为单位运行。当级别为100(SQL 2008)时,它有时需要一分钟,有时以毫秒为单位运行
我很感激任何人对此有任何见解
编辑 脚本用我的实际数据运行需要一分钟,它的行数比我在这里显示的要多,是一个真实的表,并且有一个索引。 在下面的示例代码中,差异在毫秒和大约5秒之间
--use [master]
--ALTER DATABASE MyDB SET compatibility_level =100
use [MyDB]
declare @xml xml
set @xml = '<?xml version="1.0"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Record>
<SampleTime>2009-01-24T00:00:00</SampleTime>
<Volume1>0</Volume1>
<Volume2>0</Volume2>
</Record>
..... 653 records, sample time spaced out 4 hours ........
</Root>'
DECLARE @myTable TABLE(
ID int IDENTITY(1,1) NOT NULL,
[SampleTime] [datetime] NOT NULL,
[Volume1] [float] NULL,
[Volume2] [float] NULL)
INSERT INTO @myTable
select
T.Item.value('SampleTime[1]', 'datetime') as SampleTime,
Volume1 = T.Item.value('Volume1[1]', 'float'),
Volume2 = T.Item.value('Volume2[1]', 'float')
FROM @xml.nodes('//Root/Record') T(item)
——使用[master]
--ALTER DATABASE MyDB集合兼容性\u级别=100
使用[MyDB]
声明@xml
set@xml=
2009-01-24T00:00:00
0
0
..... 653条记录,采样时间间隔为4小时。。。。。。。。
'
声明@myTable表(
ID int标识(1,1)不为空,
[SampleTime][datetime]不为空,
[Volume1][float]空,
[Volume2][float]NULL)
插入@myTable
挑选
T.Item.value('SampleTime[1],'datetime')作为SampleTime,
Volume1=T.Item.value('Volume1[1],'float'),
Volume2=T.Item.value('Volume2[1],'float')
来自@xml.nodes('//Root/Record')T(项)
我取消注释顶部的两行,选择它们并运行它(alterdatabase语句),然后注释这两行,取消选择任何文本并运行整个过程
当我从90变为100时,它会在5秒钟内一直运行(我更改了一次级别,但我运行了几次系列以查看是否有一致的结果)。
当我从100变为90时,它一直以毫秒为单位运行。
只是为了让你也能玩它。
我正在使用SQL Server 2008 R2标准版。顺便说一句,遇到此问题的任何其他人都可能会发现这有一定的用处。根据兼容性设置,查询的x-path部分的公式化方式的细微差异可能会对性能产生很大影响
起初,我找不到关于兼容性设置为何会显著改变性能的完整解释,但从那时起,Martin Smith的回答和Microsoft Connect网站上的报告解释说,这很可能是SQL 2008中的一个缺陷,我使用的兼容性设置有一个修补程序以及其他一些解决方法SQLServerCentral上的原始链接就是其中之一。这是SQLServer2008中的一个错误 如本程序所示,可通过启用TraceFlag 4130进行修复
USE [MyDB]
--Comment / Uncomment the next two lines as appropriate to test the effect with the TF turned on or off
DBCC TRACEON(4130,-1)
--DBCC TRACEOFF(4130,-1)
GO
DBCC FREEPROCCACHE
GO
declare @xmlstring varchar(max) = '<?xml version="1.0"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">'
SELECT @xmlstring +=
'<Record>
<SampleTime>2009-01-24T00:00:00</SampleTime>
<Volume1>0</Volume1>
<Volume2>0</Volume2>
</Record>'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 653
set @xmlstring += '</Root>'
DECLARE @xml xml = @xmlstring
SELECT @xml
DECLARE @myTable TABLE(
ID int IDENTITY(1,1) NOT NULL,
[SampleTime] [datetime] NOT NULL,
[Volume1] [float] NULL,
[Volume2] [float] NULL)
INSERT INTO @myTable
select
T.item.value('SampleTime[1]', 'datetime') as SampleTime,
Volume1 = T.item.value('Volume1[1]', 'float'),
Volume2 = T.item.value('Volume2[1]', 'float')
FROM @xml.nodes('//Root/Record') T(item)
使用[MyDB]
--根据需要注释/取消注释下两行,以测试TF打开或关闭时的效果
DBCC跟踪(4130,-1)
--DBCC TRACEOFF(4130,-1)
去
DBCC FREEPROCCACHE
去
声明@xmlstring varchar(max)='
'
选择@xmlstring+=
'
2009-01-24T00:00:00
0
0
'
从主..spt_值
其中type='P'和数字介于1和653之间
设置@xmlstring+=“”
声明@xml=@xmlstring
选择@xml
声明@myTable表(
ID int标识(1,1)不为空,
[SampleTime][datetime]不为空,
[Volume1][float]空,
[Volume2][float]NULL)
插入@myTable
挑选
T.item.value('SampleTime[1],'datetime')作为SampleTime,
Volume1=T.item.value('Volume1[1],'float'),
Volume2=T.item.value('Volume2[1],'float')
来自@xml.nodes('//Root/Record')T(项)
相关项目中提到了各种其他解决方法。您是想修复它,还是只想了解它为什么会改变?我想了解并修复它我还没有机会弄清楚如何修复它(或它为什么会发生),但在compat 100 for me中时,查询计划会为每个表值函数生成额外的表假脱机-这将考虑所需的额外时间,因为这些值正在写入tempdb。如果我提出了一个解决方案,我会给出一个答案——但如果我找不到时间或解决方案,希望这可以为您指明正确的方向:)。不过,这是一个伟大的发现!这是一个已知的错误,请参阅我的答案以了解详细信息。谢谢Martin,我将把我的答案保留在这里以供参考。不过,希望人们在投票时能轻松一点;)谢谢你。我在一个MSDTC事务超时(1分钟)的客户站点遇到了这个问题。我不知道这个bug,但使用
text()
获取值修复了它。起初,我无法在安装时复制此内容,但我发现它在某种程度上取决于“最大服务器内存”设置。例如,在2GB服务器上使用500 MB的值不会有任何问题。将最大内存设置为700,上述代码需要5秒而不是53毫秒。@MikaelEriksson-很有趣。不知道为什么会有影响。在执行计划属性中,“提前终止声明的原因”是什么?在fast的情况下是“超出内存限制”吗?如果是这样的话,也许它从来没有考虑过