将大型 XML 导入 SQL-Server 表的最快方法
Posted
技术标签:
【中文标题】将大型 XML 导入 SQL-Server 表的最快方法【英文标题】:Fastest method to import large XML into SQL-Server table 【发布时间】:2020-07-10 14:33:09 【问题描述】:我有一个非常大而且不是很漂亮的 XML,我想将它导入到我的 sql-server 数据库中。 XML的格式就像我说的很丑:
<myxml xmlns="http://somenamespace.whatever.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<mydata>
<item>
<record>some</record>
<record>123</record>
<record xs:nil="true" />
<record>random</record>
<record>234</record>
</item>
<item>
<record>345</record>
<record>in all</record>
<record>these</record>
<record>cells</record>
<record>123asdf</record>
</item>
<item>
<record>how</record>
<record>to</record>
<record>import</record>
<record>987654321</record>
<record xs:nil="true" />
</item>
</mydata>
</myxml>
这只是一个小样本。事实上,XML 超过 100ML,它有超过 200k 的项目,每个项目有 15 条记录,但这个样本就可以了。
我知道“项目”中的每个“记录”代表什么,但对我来说,它足以将所有记录值导入到带有 varchar(100) 的列中。让我们说这张表:”
CREATE TABLE [dbo].[DataFromXml](
[Column1] [varchar](100) NULL,
[Column2] [varchar](100) NULL,
[Column3] [varchar](100) NULL,
[Column4] [varchar](100) NULL,
[Column5] [varchar](100) NULL
) ON [PRIMARY]
GO
我可以用这段代码完成这个:
CREATE TABLE XmlTable
(
XMLData XML
)
INSERT INTO XmlTable(XMLData)
SELECT CONVERT(XML, BulkColumn)
FROM OPENROWSET(BULK 'D:\myverylarge.xml', SINGLE_CLOB) AS x;
DECLARE @XML AS XML
SELECT @XML=XMLData FROM XmlTable
;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' as xs, DEFAULT 'http://somenamespace.whatever.com/schemas/xmldata/1/')
INSERT INTO DataFromXml(Column1, Column2, Column3, Column4, Column5)
SELECT ref.value('record[1][not(@xs:nil = "true")]' ,'varchar(100)') as Column1
,ref.value('record[2][not(@xs:nil = "true")]' ,'varchar(100)') as Column2
,ref.value('record[3][not(@xs:nil = "true")]' ,'varchar(100)') as Column3
,ref.value('record[4][not(@xs:nil = "true")]' ,'varchar(100)') as Column4
,ref.value('record[5][not(@xs:nil = "true")]' ,'varchar(100)') as Column5
FROM @XML.nodes('/myxml/mydata/item') xmlData( ref )
这会运行一两分钟,这可能还不错。我没有很好的参考。我的感觉是,这可能会快很多,因为使用 OPENROWSET 将 XML(超过 100MB)导入数据库只需几秒钟。
我可以优化插入吗?如果可以,我该怎么做?
【问题讨论】:
“因为使用 OPENROWSET 将 XML(超过 100MB)放入数据库只需要几秒钟。” - 当然?或“在没有任何解析的情况下读取文件”需要几秒钟。您在那里进行了大量的处理,OPENROWSET 恕我直言不这样做。一点也不像。 我从来没有比较过,但你也可以试试 OpenXml()。 【参考方案1】:处理 NULL 值是 XML 中的特殊之处。
XML 中 NULL 值的定义不存在。所以
<a>
<b>hi</b>
<c></c>
<d/>
</a>
<a>
是根元素。
<b>
是一个带有 text()
节点的元素。
<c>
是一个空元素
<d>
是一个自闭合元素
<e>
是 - 嗯 - 不在那里......
重要提示:<c>
和<d>
是一样的,绝对没有区别!
你可以用
查询元素.value('(/a/b)[1]','nvarchar(100)')
您可以专门查询text()
节点
.value('(/a/b/text())[1]','nvarchar(100)')
在此您可以找到一个可能的答案(有点隐藏):如果您专门查询 text()
节点,您可以在没有 NULL 检查谓词的情况下执行所有代码。
改变这个
ref.value('record[1][not(@xs:nil = "true")]' ,'varchar(100)')
到这里
ref.value('(record[1]/text())[1]' ,'varchar(100)')
可能会破坏这一点:如果<record>
的内容可能是一个空字符串,您将得到一个NULL
,而不是''
。但它应该快得多......希望,这对你来说没问题......
关于性能:阅读this 答案。它很好地涵盖了您的问题。尤其是消耗时间的部分(按照此答案中的链接进行操作)。
【讨论】:
【参考方案2】:只是为了补充@Shnugo 的答案。
所有功劳归他所有。
这是您的确切 SQL 语句。它应该会给你大约 20% 的性能提升。请试一试。
;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' as xs, DEFAULT 'http://somenamespace.whatever.com/schemas/xmldata/1/')
INSERT INTO DataFromXml(Column1, Column2, Column3, Column4, Column5)
SELECT ref.value('(record[1]/text())[1]' ,'varchar(100)') as Column1
,ref.value('(record[2]/text())[1]' ,'varchar(100)') as Column2
,ref.value('(record[3]/text())[1]' ,'varchar(100)') as Column3
,ref.value('(record[4]/text())[1]' ,'varchar(100)') as Column4
,ref.value('(record[5]/text())[1]' ,'varchar(100)') as Column5
FROM @XML.nodes('/myxml/mydata/item') xmlData(ref);
【讨论】:
谢谢,Yitzhak,我的功劳归于你,我这边 +1 :-) 谢谢@Shnugo 和Yitzhak。我一定会试一试的。那么 INSERT INTO 怎么样,我们可以用更有效的语句替换它吗? @Stackberg,INSERT
声明没有错。以上是关于将大型 XML 导入 SQL-Server 表的最快方法的主要内容,如果未能解决你的问题,请参考以下文章