Sql server XML服务器XML性能优化
我在一个数据库中有34行,每行有一列包含xml——xml实际上在一个NVARCHAR(MAX)列中,而不是xml列中 对于每一行,我选择xml元素中的值作为单个结果集。表演很差。我试过两个不同的问题。第一次执行大约需要22秒,第二次执行大约需要7秒 即使是7秒,这也远比最佳速度慢,我希望最多1-2秒 因此,我在网上读到一则传言,如果您使用临时表或表变量将NVARCHAR数据转换为XML,您将获得性能提升,至少在我的情况下是如此。。。它现在在不到一秒钟的时间内执行。我现在想要的是一个解释,可以告诉我为什么这两种方法会影响性能 22秒:Sql server XML服务器XML性能优化,sql-server,xml,performance,sql-server-2012,Sql Server,Xml,Performance,Sql Server 2012,我在一个数据库中有34行,每行有一列包含xml——xml实际上在一个NVARCHAR(MAX)列中,而不是xml列中 对于每一行,我选择xml元素中的值作为单个结果集。表演很差。我试过两个不同的问题。第一次执行大约需要22秒,第二次执行大约需要7秒 即使是7秒,这也远比最佳速度慢,我希望最多1-2秒 因此,我在网上读到一则传言,如果您使用临时表或表变量将NVARCHAR数据转换为XML,您将获得性能提升,至少在我的情况下是如此。。。它现在在不到一秒钟的时间内执行。我现在想要的是一个解释,可以告诉
SELECT
c.ID,
c.ChannelName,
[Name] = d.c.value('name[1]','varchar(100)'),
[Type] = d.c.value('transportName[1]','varchar(100)'),
[Enabled] = d.c.value('enabled[1]','BIT'),
[Queued] = d.c.value('properties[1]/destinationConnectorProperties[1]/queueEnabled[1]','varchar(100)'),
[RetryInterval] = d.c.value('properties[1]/destinationConnectorProperties[1]/retryIntervalMillis[1]','INT'),
[MaxRetries] = d.c.value('properties[1]/destinationConnectorProperties[1]/retryCount[1]','INT'),
[RotateQueue] = d.c.value('properties[1]/destinationConnectorProperties[1]/rotate[1]','BIT'),
[ThreadCount] = d.c.value('properties[1]/destinationConnectorProperties[1]/threadCount[1]','INT'),
[WaitForPrevious] = d.c.value('waitForPrevious[1]','BIT'),
[Destination] = COALESCE(
d.c.value('properties[1]/channelId[1]','varchar(100)'),
d.c.value('properties[1]/remoteAddress[1]','varchar(100)'),
d.c.value('properties[1]/wsdlUrl[1]','varchar(1024)')),
[DestinationPort] = COALESCE(
d.c.value('properties[1]/remotePort[1]','varchar(100)'),
d.c.value('properties[1]/port[1]','varchar(1024)')),
[Service] = d.c.value('properties[1]/service[1]','varchar(1024)'),
[Operation] = d.c.value('properties[1]/operation[1]','varchar(1024)')
FROM
(
SELECT
[ID],
[ChannelName] = [Name],
[CFG] = Convert(XML, Channel)
FROM
dbo.CHANNEL
) c
CROSS APPLY c.CFG.nodes('/channel/destinationConnectors/connector') d(c)
7秒,由于使用了text()。我不知道为什么文字会加快速度
SELECT
c.ID,
c.ChannelName,
[Name] = d.c.value('(name/text())[1]','varchar(100)'),
[Type] = d.c.value('(transportName/text())[1]','varchar(100)'),
[Enabled] = d.c.value('(enabled/text())[1]','BIT'),
[Queued] = d.c.value('(properties/destinationConnectorProperties/queueEnabled/text())[1]','varchar(100)'),
[RetryInterval] = d.c.value('(properties/destinationConnectorProperties/retryIntervalMillis/text())[1]','INT'),
[MaxRetries] = d.c.value('(properties/destinationConnectorProperties/retryCount/text())[1]','INT'),
[RotateQueue] = d.c.value('(properties/destinationConnectorProperties/rotate/text())[1]','BIT'),
[ThreadCount] = d.c.value('(properties/destinationConnectorProperties/threadCount/text())[1]','INT'),
[WaitForPrevious] = d.c.value('(waitForPrevious/text())[1]','BIT'),
[Destination] = COALESCE(
d.c.value('(properties/channelId/text())[1]','varchar(100)'),
d.c.value('(properties/remoteAddress/text())[1]','varchar(100)'),
d.c.value('(properties/wsdlUrl/text())[1]','varchar(1024)')),
[DestinationPort] = COALESCE(
d.c.value('(properties/remotePort/text())[1]','varchar(100)'),
d.c.value('(properties/port/text())[1]','varchar(1024)')),
[Service] = d.c.value('(properties/service/text())[1]','varchar(1024)'),
[Operation] = d.c.value('(properties/operation/text())[1]','varchar(1024)')
FROM
(
SELECT
[ID],
[ChannelName] = [Name],
[CFG] = Convert(XML, Channel)
FROM
dbo.CHANNEL
) c
CROSS APPLY c.CFG.nodes('/channel/destinationConnectors/connector') d(c)
此查询使用text()方法,但puts首先将NVARCHAR列转换为表变量中的xml列。在不到一秒钟内执行
DECLARE @Xml AS TABLE (
[ID] NVARCHAR(36) NOT NULL Primary Key,
[Name] NVARCHAR(100) NOT NULL,
[CFG] XML NOT NULL
);
INSERT INTO @Xml (ID, Name, CFG)
SELECT
c.ID,
c.Name,
Convert(XML, c.Channel)
FROM
[dbo].[CHANNEL] c;
SELECT
c.ID,
c.ChannelName,
[Name] = d.c.value('(name/text())[1]','varchar(100)'),
[Type] = d.c.value('(transportName/text())[1]','varchar(100)'),
[Enabled] = d.c.value('(enabled/text())[1]','BIT'),
[Queued] = d.c.value('(properties/destinationConnectorProperties/queueEnabled/text())[1]','varchar(100)'),
[RetryInterval] = d.c.value('(properties/destinationConnectorProperties/retryIntervalMillis/text())[1]','INT'),
[MaxRetries] = d.c.value('(properties/destinationConnectorProperties/retryCount/text())[1]','INT'),
[RotateQueue] = d.c.value('(properties/destinationConnectorProperties/rotate/text())[1]','BIT'),
[ThreadCount] = d.c.value('(properties/destinationConnectorProperties/threadCount/text())[1]','INT'),
[WaitForPrevious] = d.c.value('(waitForPrevious/text())[1]','BIT'),
[Destination] = COALESCE(
d.c.value('(properties/channelId/text())[1]','varchar(100)'),
d.c.value('(properties/remoteAddress/text())[1]','varchar(100)'),
d.c.value('(properties/wsdlUrl/text())[1]','varchar(1024)')),
[DestinationPort] = COALESCE(
d.c.value('(properties/remotePort/text())[1]','varchar(100)'),
d.c.value('(properties/port/text())[1]','varchar(1024)')),
[Service] = d.c.value('(properties/service/text())[1]','varchar(1024)'),
[Operation] = d.c.value('(properties/operation/text())[1]','varchar(1024)')
FROM
(
SELECT
[ID],
[ChannelName] = [Name],
[CFG]
FROM
@Xml
) c
CROSS APPLY c.CFG.nodes('/channel/destinationConnectors/connector') d(c)
我可以给你一个答案和一个猜测: 首先,我使用声明的表变量模拟您的场景:
DECLARE @tbl TABLE(s NVARCHAR(MAX));
INSERT INTO @tbl VALUES
(N'<root>
<SomeElement>This is first text of element1
<InnerElement>This is text of inner element1</InnerElement>
This is second text of element1
</SomeElement>
<SomeElement>This is first text of element2
<InnerElement>This is text of inner element2</InnerElement>
This is second text of element2
</SomeElement>
</root>')
,(N'<root>
<SomeElement>This is first text of elementA
<InnerElement>This is text of inner elementA</InnerElement>
This is second text of elementA
</SomeElement>
<SomeElement>This is first text of elementB
<InnerElement>This is text of inner elementB</InnerElement>
This is second text of elementB
</SomeElement>
</root>');
--第二部分使用表写入类型化XML并从中读取:
DECLARE @tbl2 TABLE(x XML)
INSERT INTO @tbl2
SELECT CAST(s AS XML) FROM @tbl;
SELECT se.value(N'(.)[1]','nvarchar(max)') SomeElementsContent
,se.value(N'(InnerElement)[1]','nvarchar(max)') InnerElementsContent
,se.value(N'(./text())[1]','nvarchar(max)') ElementsFirstText
,se.value(N'(./text())[2]','nvarchar(max)') ElementsSecondText
FROM @tbl2 t2
CROSS APPLY t2.x.nodes(N'/root/SomeElement') AS A(se);
为什么/text()
比没有/text()
的速度快?
如果看我的示例,元素的内容包括从开始标记到结束标记的所有内容。元素的text()
是这些标记之间的浮动文本。您可以在上面选择的结果中看到这一点。text()。要获取它,需要一步操作。否则,必须分析一个复杂的结构,以找到开始标记和相应结束标记之间的所有内容-即使除了text()
之外没有其他内容
为什么要将XML存储在适当的类型中?
XML不仅仅是带有一些愚蠢的额外字符的文本!这是一份结构复杂的文件。XML不会存储为您看到的文本。XML存储在树结构中。每当您将表示XML的字符串转换为真正的XML时,都必须完成这项非常昂贵的工作。当XML呈现给您(或任何其他输出)时,将从头开始(重新)构建表示字符串
为什么预制方法更快
这是猜测…
在我的示例中,这两种方法相当相等,并且导致(几乎)相同的执行计划。
SQL Server不会像您预期的那样处理所有问题。这不是一个程序系统,您可以声明执行此操作,然后再执行此操作!。你告诉引擎你想要什么,引擎决定如何做到最好。而且这个引擎很好用
在执行开始之前,引擎会尝试估计方法的成本<代码>转换
(或转换
)是一种相当便宜的操作。引擎可能会决定记下您的调用列表,并一遍又一遍地为每个单独的需求进行转换,因为它认为这比昂贵的派生表创建要便宜…检查执行计划
,它们实际上是相同的。至少我看不出有什么可以归因于性能的差异。@Jeremy,如果您想了解更深入的情况,可以开始。还有一些很棒的链接。
DECLARE @tbl2 TABLE(x XML)
INSERT INTO @tbl2
SELECT CAST(s AS XML) FROM @tbl;
SELECT se.value(N'(.)[1]','nvarchar(max)') SomeElementsContent
,se.value(N'(InnerElement)[1]','nvarchar(max)') InnerElementsContent
,se.value(N'(./text())[1]','nvarchar(max)') ElementsFirstText
,se.value(N'(./text())[2]','nvarchar(max)') ElementsSecondText
FROM @tbl2 t2
CROSS APPLY t2.x.nodes(N'/root/SomeElement') AS A(se);