SQL Server: OPENXML vs SELECT..FROM при работе с XML?

У меня есть этот 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

вопрос:

который является предпочтительным способом?

Есть ли какие-либо преимущества последнего против прежнего (или наоборот)?

Ответ 1

Простой тест показывает, что ваш подход 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.)

Ответ 2

Я предпочитаю # 2. попробуйте выполнить план выполнения и убедитесь, что первый аспект составляет 97%, а в случае, если конв стоит всего 3%

enter image description here

Ответ 3

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