SQL Server:处理XML时OPENXML与SELECT..FROM?

时间:2012-03-08 07:52:00

标签: sql sql-server xml sql-server-2005 tsql

我有这个xml:

DECLARE @x XML
SET @x = 
    '<data>
       <add>a</add>
       <add>b</add>
       <add>c</add>
     </data>';

任务:

我想列出a,b,c

接近1:

SELECT s.value('.', 'VARCHAR(8000)') AS [ADD]
FROM   @x.nodes('/data/add') AS t(s) 

接近2:

DECLARE @idoc INT
EXEC sp_xml_preparedocument @idoc OUTPUT, @x

SELECT *
FROM   OPENXML(@idoc, '/data/add', 2)
       WITH ([add] NVARCHAR(MAX) '.')

他们都给了我:

enter image description here

问题:

哪种方式首选?

后者与前者(或反之亦然)有什么好处吗?

3 个答案:

答案 0 :(得分:9)

一个简单的测试表明,方法1 方法2 花费更少的时间。关于它总是如此,我不会得出任何结论。它取决于XML的结构以及查询XML的方式。

要测试的存储过程:

create procedure TestXML
  @X xml
as
set nocount on

select X.N.value('.', 'varchar(8000)')
from @X.nodes('/root/item') as X(N)

go

create procedure TestOpenXML
  @X xml
as
set nocount on

declare @idoc int
exec sp_xml_preparedocument @idoc out, @X

select value
from openxml(@idoc, '/root/item',1) 
  with (value  varchar(8000) '.')

exec sp_xml_removedocument @idoc

测试:

declare @X xml

set @X =
  (
    select number as '*'
    from master..spt_values
    for xml path('item'), root('root'), type
  )

set statistics time on
exec TestXML @X
exec TestOpenXML @X

结果方法1:

SQL Server Execution Times:
   CPU time = 63 ms,  elapsed time = 70 ms.

结果方法2:

SQL Server Execution Times:
   CPU time = 156 ms,  elapsed time = 159 ms.

(在SQL Server 2005上测试过。)

答案 1 :(得分:2)

我更喜欢#2。尝试执行计划,看第一种方法成本为97%而第二种成本仅为3%

enter image description here

答案 2 :(得分:0)

SET NOCOUNT ON;
DECLARE @BankXml VARCHAR(MAX) = '<ROOT><ITEM BAF="HI" /></ROOT>'
DECLARE @ErrMsg VARCHAR(MAX) ='',@XmlId INT,@TranCount INT
CREATE TABLE #tmptbl(BAF VARCHAR(10))
IF (@BankXml IS NOT NULL)        
    BEGIN        
        EXEC SP_XML_PREPAREDOCUMENT @XmlId OUTPUT, @BankXml
        INSERT INTO #tmptbl(BAF)
        SELECT BAF
        FROM OPENXML(@XmlId, 'ROOT/ITEM', 1) WITH
        (
            BAF VARCHAR(10)
        )                           
    END 
BEGIN TRY
    IF @@TRANCOUNT = 0
        SET @TranCount = 1
    IF @TranCount=1 
        BEGIN TRAN
    IF 1=1
    BEGIN
        SELECT BAF FROM #tmptbl
    END     
    IF @TranCount = 1
        COMMIT TRAN
END TRY
BEGIN CATCH
    IF @@TRANCOUNT = 1 AND @TranCount = 1
    ROLLBACK TRAN
    SET @ErrMsg = 'Error : ' + @ErrMsg + ' : ' + ERROR_MESSAGE()
    RAISERROR(@ErrMsg,16,1)
END CATCH