Sql server 需要进行XML SQL优化

Sql server 需要进行XML SQL优化,sql-server,xml,tsql,optimization,xquery,Sql Server,Xml,Tsql,Optimization,Xquery,您好,我一直在尝试将SQL中XML的组和字段插入到两个表中。但解决方案要么不能解决我的问题,要么性能很慢,因为组和字段的数量可能会达到数十万 XML的一个示例: <?xml version="1.0" encoding="utf-16"?> <FB_Flow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="htt

您好,我一直在尝试将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 @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)
我一直通过使用光标并通过position属性选择组来解决这个问题,但是性能非常差

   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版本是什么选择@@version

请在没有光标的情况下尝试以下方法。它将给您带来巨大的性能改进:

XML属性不需要[1]位置。属性总是唯一的。 XML元素需要在XPath表达式文本中进行调整。 SQL


很好,解决了我的问题,谢谢,解释得很好。@JeffCorn,很高兴听到建议的解决方案对您有效。请别忘了把它标为答案。另外,请在这里投票:
   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
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);