J. *_*man 4 xml sql t-sql sql-server
我目前正在尝试在T-SQL中创建一个存储过程,该存储过程将XML表作为输入,然后将数据插入到临时表中。
我正在使用的XML具有以下格式:
<Table>
    <row MyFirstColumn="foo" MySecondColumn="bar" ... />
</Table>
Run Code Online (Sandbox Code Playgroud)
我用于将此XML数据插入临时表的SQL具有以下格式:
INSERT INTO
    #TempTable
SELECT
    T.c.value('@MyFirstColumn', 'varchar(50)')
   ,T.c.value('@MySecondColumn', 'varchar(50)')
   ,...
FROM
    @x.nodes('//Table/row') T(c)
Run Code Online (Sandbox Code Playgroud)
但是,我使用包含150列和200,000行以上的XML表来执行此操作。目前,在10,000行上执行此SQL大约需要142秒,因此,这对于处理包含大量行的XML表是完全不合适的。
谁能建议一种加快此过程的方法?
查询大量列时,在SQL Server中使用node()/ value()分解XML具有性能问题。有一个嵌套循环联接,其中每一列都调用xml函数。
3列查询计划:
5列查询计划:
试想一下,超过150列会是什么样子。
您的另一个选择是使用OPENXML。对于许多列,它没有相同的问题。
您的查询如下所示:
declare @H int;
declare @X xml;
exec sys.sp_xml_preparedocument @H output,
                                @X;
select C1,
       C2,
       C3
from
       openxml(@H, 'Table/row', 0)
       with (
              C1 int,
              C2 int,
              C3 int
            );
exec sys.sp_xml_removedocument @H;
Run Code Online (Sandbox Code Playgroud)
对我而言,使用nodes()/ value()使用150列和1000行需要大约14秒,而使用OPENXML需要3秒。
用于测试的代码;
drop table T;
go
declare @C int = 150;
declare @S nvarchar(max);
declare @X xml;
declare @N int = 1000;
declare @D datetime;
set @S = 'create table T('+
stuff((
      select top(@C) ', '+N'C'+cast(row_number() over(order by 1/0) as nvarchar(3)) + N' int'
      from sys.columns
      for xml path('')
      ), 1, 2, '') + ')'
exec sp_executesql @S;
set @S = 'insert into T select top(@N) '+
stuff((
      select top(@C) ',1'
      from sys.columns as c1
      for xml path('')
      ), 1, 1, '') + ' from sys.columns as c1, sys.columns as c2';
exec sp_executesql @S, N'@N int', @N;
set @X = (
         select *
         from dbo.T
         for xml raw, root('Table')
         );
set @S = 'select '+
stuff((
      select top(@C) ', '+N'T.X.value(''@C'+cast(row_number() over(order by 1/0) as nvarchar(3)) + N''', ''int'')'
      from sys.columns
      for xml path('')
      ), 1, 2, '') + ' from @X.nodes(''Table/row'') as T(X)'
set @D = getdate();
exec sp_executesql @S, N'@X xml', @X;
select datediff(second, @D, getdate());
set @S = 'declare @H int;
exec sp_xml_preparedocument @H output, @X;
select *
from openxml(@H, ''Table/row'', 0)
  with (' +
stuff((
      select top(@C) ', C'+cast(row_number() over(order by 1/0) as nvarchar(3))+ ' int'
      from sys.columns
      for xml path('')
      ), 1, 2, '') + ');
exec sys.sp_xml_removedocument @H';
set @D = getdate();
exec sp_executesql @S, N'@X xml', @X
select datediff(second, @D, getdate());
Run Code Online (Sandbox Code Playgroud)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           2763 次  |  
        
|   最近记录:  |