В настоящее время мы используем OUTPUT для INSERT и UPDATE в хранимых процедурах, чтобы объединить строку для преобразования в XML для отслеживания того, что было изменено. Затем этот XML помещается в UDT и передается другой процедуре, где он анализируется и помещается в физическую таблицу отслеживания.
Мы отслеживаем имя таблицы, значение PK строки изменилось, столбец изменился, старые и новые значения, идентификатор пакета для определения значений, измененных одновременно, а также кто / когда измененное.
Процедура синтаксического анализа XML с целью его включения в фактическую таблицу отслеживания является существенным узким местом производительности. Я пытаюсь придумать альтернативы этому, но у меня мало шансов. Единственное, о чем я могу думать, это, возможно, какой-то PIVOT в запросе OUTPUT, чтобы поместить значения в UDT в их исходной форме, а не в конкатенацию в XML.
Это образец оператора 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)
Proc делает немного больше вещей перед тем, как вставлять в таблицу отслеживания. Однако XQuery составляет 99,9% - 100% от плана выполнения. В идеале, я думаю, лучше всего было бы полностью избавиться от XML и XQuery. Просто не знаю как.