【问题标题】:XML SQL Optimization needed需要 XML SQL 优化
【发布时间】:2021-04-01 07:03:30
【问题描述】:

您好,我一直试图从 SQL 中的 XML 插入两个表(组和字段)。但该解决方案要么无法解决我的问题,要么性能很慢,因为组和字段的数量可能达到数十万。

XML 示例:

<?xml version="1.0" encoding="utf-16"?>
<FB_Flow
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="1">
    <groups>
        <FB_FlowGroup counter="1125" position="2" positionparent="0" id="0">
            <fields>
                <FB_FlowField>
                    <value>TEST1</value>
                    <counter>111</counter>
                    <lineposition>1</lineposition>
                </FB_FlowField>
                <FB_FlowField>
                    <value>TEST2</value>
                    <counter>222</counter>
                    <lineposition>2</lineposition>
                    <groupid>0</groupid>
                </FB_FlowField>
                <FB_FlowField>
                    <value>TEST3</value>
                    <counter>333</counter>
                    <lineposition>3</lineposition>
                </FB_FlowField>
            </fields>
        </FB_FlowGroup>
        <FB_FlowGroup counter="1126" position="3" positionparent="2" id="0">
            <fields>
                <FB_FlowField>
                    <value>TEST1</value>
                    <counter>18</counter>
                    <lineposition>1</lineposition>
                </FB_FlowField>
            </fields>
        </FB_FlowGroup>     
    </groups>
</FB_Flow> 

第一部分工作正常(获取所有组的列表)

   insert into @Groups (intGroupCounter,intGroupPosition,intGroupPositionParent)
   SELECT
        gcounter = Groups.value('@counter[1]', 'int'),
        gposition = Groups.value('@position[1]', 'int'),
        gpositionparent = Groups.value('@positionparent[1]', 'int')
FROM
        @FlowXML.nodes('/FB_Flow/groups/FB_FlowGroup') AS XTbl(Groups)

第二部分大部分都失败了(获取所有具有父组位置的字段):

   insert into @Fields (intGroupPosition,vFieldValue,intFieldCounter,intFieldPosition)
       SELECT
        gposition = XTbl.Groups.value('@position', 'int'),
        fValue = XTbl2.Fields.value('value[1]', 'varchar(max)'),
        fcounter = XTbl2.Fields.value('counter[1]', 'int'),
        fposition = XTbl2.Fields.value('lineposition[1]', 'int')
FROM
        @FlowXML.nodes('/FB_Flow/groups/FB_FlowGroup') AS XTbl(Groups)
cross APPLY
    Groups.nodes('fields/FB_FlowField') AS XTbl2(Fields)

我一直通过使用光标并按位置属性选择组来解决这个问题,但性能很差。

   DECLARE @GroupCounter int,
            @GroupPosition int,
            @GroupPositionParent int,
            @GroupID int
            
   DECLARE @Groups table
   (
        intGroupCounter int not null,
        intGroupPosition int not null,
        intGroupPositionParent int null default 0
   )
            
   insert into @Groups (intGroupCounter,intGroupPosition,intGroupPositionParent)
   SELECT
        gcounter = Groups.value('@counter[1]', 'int'),
        gposition = Groups.value('@position[1]', 'int'),
        gpositionparent = Groups.value('@positionparent[1]', 'int')
FROM
        @FlowXML.nodes('/FB_Flow/groups/FB_FlowGroup') AS XTbl(Groups)

   DECLARE cur cursor for 
   SELECT
        intGroupCounter,
        intGroupPosition,
        intGroupPositionParent
    FROM
        @Groups

    OPEN cur

    FETCH NEXT FROM cur INTO @GroupCounter, @GroupPosition, @GroupPositionParent

    WHILE @@FETCH_STATUS = 0
    BEGIN
        insert into FB_T_FlowGroups (FH_ID,DTC_GroupCounter,Position,PositionParent)
        values (@FlowHeaderID,@GroupCounter,@GroupPosition,@GroupPositionParent)

        select @GroupID = @@IDENTITY 

        --declare @Path varchar(max) = '/FB_Flow/groups/FB_FlowGroup[@position="sql:variable("@GroupPosition")"]/fields/FB_FlowField' 
        
        insert into FB_T_FlowGroupField (FlowGroupID,ItemValue,DTC_ItemCounter)
        SELECT
            @GroupID,
            XTbl.Fields.value('value[1]', 'varchar(max)'),
            XTbl.Fields.value('counter[1]', 'int')
        FROM
            @FlowXML.nodes('/FB_Flow/groups/FB_FlowGroup[@position=sql:variable("@GroupPosition")]/fields/FB_FlowField') AS XTbl(Fields)
        

        FETCH NEXT FROM cur INTO @GroupCounter, @GroupPosition, @GroupPositionParent
    END
    CLOSE cur
    DEALLOCATE cur

有什么想法吗?

【问题讨论】:

    标签: sql-server xml tsql optimization xquery


    【解决方案1】:

    您的 SQL Server 版本是多少 (SELECT @@VERSION;)?

    请在没有光标的情况下尝试以下方法。它应该会给您带来巨大的性能提升:

    • XML 属性不需要 [1] 位置。属性始终是唯一的。
    • XML 元素需要在 XPath 表达式中进行调整 - text()

    SQL

    DECLARE @FlowXML XML =
    N'<FB_Flow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="1">
        <groups>
            <FB_FlowGroup counter="1125" position="2" positionparent="0" id="0">
                <fields>
                    <FB_FlowField>
                        <value>TEST1</value>
                        <counter>111</counter>
                        <lineposition>1</lineposition>
                    </FB_FlowField>
                    <FB_FlowField>
                        <value>TEST2</value>
                        <counter>222</counter>
                        <lineposition>2</lineposition>
                        <groupid>0</groupid>
                    </FB_FlowField>
                    <FB_FlowField>
                        <value>TEST3</value>
                        <counter>333</counter>
                        <lineposition>3</lineposition>
                    </FB_FlowField>
                </fields>
            </FB_FlowGroup>
            <FB_FlowGroup counter="1126" position="3" positionparent="2" id="0">
                <fields>
                    <FB_FlowField>
                        <value>TEST1</value>
                        <counter>18</counter>
                        <lineposition>1</lineposition>
                    </FB_FlowField>
                </fields>
            </FB_FlowGroup>
        </groups>
    </FB_Flow>';
    
    -- insert into @Groups (intGroupCounter,intGroupPosition,intGroupPositionParent)
    SELECT gcounter = Groups.value('@counter', 'INT')
        , gposition = Groups.value('@position', 'INT')
        , gpositionparent = Groups.value('@positionparent', 'INT')
    FROM @FlowXML.nodes('/FB_Flow/groups/FB_FlowGroup') AS XTbl(Groups);
    
    --insert into @Fields (intGroupPosition,vFieldValue,intFieldCounter,intFieldPosition)
    SELECT gposition = XTbl.Groups.value('@position', 'INT')
        , fValue = XTbl2.Fields.value('(value/text())[1]', 'VARCHAR(MAX)')
        , fcounter = XTbl2.Fields.value('(counter/text())[1]', 'INT')
        , fposition = XTbl2.Fields.value('(lineposition/text())[1]', 'INT')
    FROM @FlowXML.nodes('/FB_Flow/groups/FB_FlowGroup') AS XTbl(Groups)
        CROSS APPLY Groups.nodes('fields/FB_FlowField') AS XTbl2(Fields);
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    相关资源
    最近更新 更多