SQL中的XML替代方案?也许是PIVOT?

时间:2019-03-20 17:45:55

标签: sql sql-server performance sql-server-2012 xquery

我们目前在存储过程中的INSERT和UPDATEs上使用OUTPUT,以连接在一起的字符串形式转换为XML,以跟踪已更改的内容。然后将该XML放入UDT中,并传递给另一个过程,在该过程中将其解析并放入物理跟踪表中。

我们正在跟踪表的名称,行的PK值已更改,列已更改,旧值和新值,用于同时标识值的批处理ID以及谁/何时改变了。

解析XML以便可以将其放入实际跟踪表的过程是一个重要的性能瓶颈。我正在尝试提出替代方法,但是我很简短。我唯一想到的可能是OUTPUT查询上的某种PIVOT,用于将值以其本机形式而不是串联为XML的形式放入UDT。

这是UPDATE末尾的OUTPUT语句的示例

DECLARE @TrackingColumnChange TrackingColumnChangeType


        OUTPUT     
            'SomeTable',    
            @SessionId,    
            @statementId,    
            INSERTED.TransactionMortgageId,
            CAST('<Columns>' +      
                   '<Column>' +     
                    '<ColumnName>SomeColumn1</ColumnName>' +     
                    '<OldValue>' + ISNULL(CAST(DELETED.SomeColumn1 AS VARCHAR(50)), '"Blank"') + '</OldValue>' +     
                    '<NewValue>' + ISNULL(CAST(INSERTED.SomeColumn1 AS VARCHAR(50)), '"Blank"') + '</NewValue>' +     
                   '</Column>' +    
                   '<Column>' +     
                    '<ColumnName>SomeColumn2</ColumnName>' +     
                    '<OldValue>' + ISNULL(CAST(DELETED.SomeColumn2 AS VARCHAR(50)), '"Blank"') + '</OldValue>' +     
                    '<NewValue>' + ISNULL(CAST(INSERTED.SomeColumn2 AS VARCHAR(50)), '"Blank"') + '</NewValue>' +     
                   '</Column>' +                                                   
               '</Columns>' AS XML),    
            NULL,    
            NULL,    
            @spSystemUserLoginId    
        INTO @TrackingColumnChange (TableName,            
                                    SessionId,    
                                    StatementId,    
                                    PrimaryKey,    
                                    TrackingData,    
                                    ContextReferenceId,    
                                    ContextReferenceType,    
                                    CreatorId
                                    )

然后解析它的查询如下:

    CREATE TABLE #Tracking ([TableName] [nvarchar](128) NOT NULL,
                        [ColumnName] [nvarchar](128) NOT NULL,
                        [SessionId] [bigint] NOT NULL,
                        [StatementId] [bigint] NOT NULL,
                        [PrimaryKey] [int] NOT NULL,
                        [OldValue] [varchar](max) NULL,
                        [NewValue] [varchar](max) NULL,
                        [ContextReferenceId] BIGINT NULL,
                        [ContextReferenceType] [nvarchar](128) NULL,
                        [CreatorId] [int] NOT NULL  
                    )

INSERT INTO #Tracking (TableName,
                        ColumnName,
                        SessionId,
                        StatementId,
                        PrimaryKey,
                        OldValue,
                        NewValue,
                        ContextReferenceId,
                        ContextReferenceType,
                        CreatorId
                    )
     SELECT TrackingColumnChange.TableName,
            ref.value('(ColumnName)[1]', 'NVARCHAR(128)'),
            TrackingColumnChange.SessionId,
            TrackingColumnChange.StatementId,
            TrackingColumnChange.PrimaryKey,
            ref.value('(OldValue)[1]', 'VARCHAR(MAX)'),
            ref.value('(NewValue)[1]', 'VARCHAR(MAX)'),
            TrackingColumnChange.ContextReferenceId,
            TrackingColumnChange.ContextReferenceType,
            TrackingColumnChange.CreatorId
       FROM @TrackingColumnChange TrackingColumnChange
CROSS APPLY TrackingColumnChange.TrackingData.nodes('Columns/Column') TrackingData(ref)

在实际插入Tracking表之前,该proc会做更多的事情。但是,XQuery是执行计划的99.9%-100%。我认为,理想情况下,最好的选择是完全摆脱XML和XQuery。只是不确定如何。

0 个答案:

没有答案