XML 加载缓慢。使用以属性为中心的映射读取 XML 文件时使用 text()

XML load is slow. Using text() when reading XML file with attribute-centric mapping

我正在将 XML 文件读入数据库。它工作正常但速度很慢。我想知道我是否可以使用 text() 来加快处理速度,类似于 post 中的解决方案:Xml select query xpath is slow.
然而,我的问题是解决方案是 XML 以元素为中心的映射,而我有以属性为中心的映射,所以我不确定如何在我的情况下使用 text()

XML 看起来像这样

<Level1>
    <Level2 name="l2_name">
        <Level3 name="l3_name">
            <Level4 name="l4_name">
                <Level5 name="l5_name">
                    <Level6_1 name="l6_1_name" value="l6_1_value"/>
                    <Level6_2 name="l6_2_name" value="l6_2_value"/>

我正在使用以下代码

declare @x xml

select @x = c1 
from openrowset(bulk 'd:\file.xml', single_blob) as table1(c1);

select
    c.value('@name', 'varchar(20)') as [col1],
    c2.value('@name', 'varchar(20)') as [col2],
    c3.value('@name', 'varchar(20)') as [col3],
    c4.value('@name', 'varchar(20)') as [col4],
    c5_1.value('@name', 'varchar(20)') as [col5],
    c5_1.value('@value', 'varchar(20)') as [col6],
    c5_2.value('@name', 'varchar(20)') as [col7],
    c5_2.value('@value', 'varchar(20)') as [col8],
from @x.nodes('Level1/Level2') as t(c)
cross apply c.nodes('Level3') as t2(c2)
cross apply c2.nodes('Level4') as t3(c3)
cross apply c3.nodes('Level5') as t4(c4)
cross apply c4.nodes('Level6_1') as t5_1(c5_1)
cross apply c4.nodes('Level6_2') as t5_2(c5_2)

我正在读取的文件是13MB,读取它需要3.5个小时。

由于无法像您那样测试那么多行,我会给您这个脚本来试用 (fiddle<>):

DECLARE @x XML=N'
<Level1><Level2 name="l2_name"><Level3 name="l3_name">
<Level4 name="l4_name"><Level5 name="l5_name">
<Level6 name="l6_name" value="l6_value"/>
<Level6 name="l6_name" value="l6_value"/>
</Level5></Level4></Level3></Level2></Level1>';

SELECT
    x.n.value('../../../../@name', 'varchar(20)') as [col1],
    x.n.value('../../../@name', 'varchar(20)') as [col2],
    x.n.value('../../@name', 'varchar(20)') as [col3],
    x.n.value('../@name', 'varchar(20)') as [col4],
    x.n.value('./@name', 'varchar(20)') as [col5]
FROM
    @x.nodes('/Level1/Level2/Level3/Level4/Level5/Level6') AS x(n);

这将显式查询 Level6 个节点,然后回溯父节点的属性值。这很可能比对每个 LevelN 元素交叉应用查询更快。


已更新,对于级别 6 中具有不同名称的元素,并假设每个名称中只有一个这样的元素作为级别 5 的子元素出现:

DECLARE @x_2 XML=N'<Level1>
    <Level2 name="l2_name">
        <Level3 name="l3_name">
            <Level4 name="l4_name">
                <Level5 name="l5_name">
                    <Level6_1 name="l6_1_name" value="l6_1_value"/>
                    <Level6_2 name="l6_2_name" value="l6_2_value"/>
                    </Level5></Level4></Level3></Level2></Level1>';

SELECT
    x.n.value('../../../@name', 'varchar(20)') as [col1],
    x.n.value('../../@name', 'varchar(20)') as [col2],
    x.n.value('../@name', 'varchar(20)') as [col3],
    x.n.value('./@name', 'varchar(20)') as [col4],
    x.n.value('(./Level6_1/@name)[1]', 'varchar(20)') as [col5],
    x.n.value('(./Level6_2/@name)[1]', 'varchar(20)') as [col6]
FROM
    @x_2.nodes('/Level1/Level2/Level3/Level4/Level5') AS x(n);

这会选择第 5 层的节点,回溯到父节点的父属性,然后根据名称选择子元素。使用 [1] 选择器选择第一个这样的元素。