J'ai configuré un courtier de service pour la première fois et je l'ai testé ... a l'air bien. Chaque fois qu'une opération DML arrive sur une table spécifique; Disons que la table de prix, une gâchette appelle une procédure stockée qui lui transmettait les tables insérées et supprimées sous forme de paramètres XML qui enverront le message (contenant les 2 XMLS) à la file d'attente.
La procédure d'activation traite ensuite la file d'attente et insère les modifications apportées au tableau initial dans une table d'audit ... fonctionne bien.
Le problème se produit lorsque la mise à jour sur la table de prix est massive. Dans mon cas, j'ai testé une mise à jour de changement de prix sur 105 000 articles. Les variables xml insérées et supprimées contiennent 1,3 million de lignes chacune ... qui provoque des problèmes majeurs: TEMPDB augmente infiniment et le processeur augmente à 95%, ce qui est compréhensible ... mais ne semble jamais compléter l'opération.
Le code de la gâchette est Price_tab_audit_trig . La gâchette appelle la procédure sendmsgservicebroker pour envoyer le message à la file d'attente. Voir les commentaires ci-dessous pour la procédure d'activation.
J'essaie de comprendre comment je peux décomposer les variables insérées et supprimées (messages) en XML plus petits. Mes questions/pensées sont: puis-je créer des variables de table et passer cela dans le message au lieu de XML? Si oui, comment créer des tables variables dans un déclencheur? Devrais-je créer des tables temporaires uniques et les références dans le message?
Toute autre suggestion, est la bienvenue. Merci d'avance JG
Vous pouvez envoyer les données XML dans des morceaux prédéfinis en utilisant quelque chose comme la gâchette dans la configuration suivante.
Créez le banc d'essai dans TEMPDB:
USE tempdb;
IF EXISTS (SELECT 1 FROM sys.triggers t WHERE t.name = 'TriggerTest_Chunked')
DROP TRIGGER dbo.TriggerTest_Chunked;
IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'TriggerTest')
DROP TABLE dbo.TriggerTest;
CREATE TABLE dbo.TriggerTest
(
ID INT NOT NULL
);
IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'TriggerTestTarget')
DROP TABLE dbo.TriggerTestTarget;
CREATE TABLE dbo.TriggerTestTarget
(
OperationType INT NOT NULL
, DEETS XML NOT NULL
);
La gâchette:
CREATE TRIGGER dbo.TriggerTest_Chunked
ON dbo.TriggerTest
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE @RowStart INT;
DECLARE @RowEnd INT;
DECLARE @RowCount INT;
DECLARE @BatchSize INT;
SET @BatchSize = 1000;
SET @RowStart = 0;
SELECT @RowCount = COUNT(1)
FROM inserted;
IF @RowCount > @BatchSize
SET @RowEnd = @BatchSize
ELSE
SET @RowEnd = @RowCount;
WHILE @RowEnd <= @RowCount AND (@RowStart < @RowEnd)
BEGIN
INSERT INTO dbo.TriggerTestTarget (OperationType, DEETS)
SELECT 1, (
SELECT ID
FROM (
SELECT *
, rn = ROW_NUMBER() OVER (ORDER BY ID)
FROM inserted
) i_rn
WHERE i_rn.rn > @RowStart
AND i_rn.rn <= @RowEnd
FOR XML PATH('')
);
SET @RowStart = @RowStart + @BatchSize;
IF @RowEnd + @BatchSize > @RowCount
SET @BatchSize = @RowCount - @RowEnd;
SET @RowEnd = @RowEnd + @BatchSize;
END
SET @RowStart = 0;
SELECT @RowCount = COUNT(1)
FROM deleted;
IF @RowCount > @BatchSize
SET @RowEnd = @BatchSize
ELSE
SET @RowEnd = @RowCount;
WHILE @RowEnd <= @RowCount AND (@RowStart < @RowEnd)
BEGIN
INSERT INTO dbo.TriggerTestTarget (OperationType, DEETS)
SELECT 2, (
SELECT ID
FROM (
SELECT *
, rn = ROW_NUMBER() OVER (ORDER BY ID)
FROM deleted
) i_rn
WHERE i_rn.rn > @RowStart
AND i_rn.rn <= @RowEnd
FOR XML PATH('')
);
SET @RowStart = @RowStart + @BatchSize;
IF @RowEnd + @BatchSize > @RowCount
SET @BatchSize = @RowCount - @RowEnd;
SET @RowEnd = @RowEnd + @BatchSize;
END
END
GO
Insérez quelques données de test pour voir ce que fait la gâchette:
INSERT INTO dbo.TriggerTest (ID)
SELECT ROW_NUMBER() OVER (ORDER BY o1.object_id, o2.object_id)
FROM sys.objects o1
, sys.objects o2;
Montrer les résultats:
SELECT *
FROM dbo.TriggerTest;
SELECT *
FROM dbo.TriggerTestTarget;
DELETE TOP(100)
FROM dbo.TriggerTest;
SELECT *
FROM dbo.TriggerTestTarget;