Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Acionador do SQL Server:Noções básicas e alternativas


O gatilho do SQL Server é um tipo especial de procedimentos armazenados que é executado automaticamente quando ocorre um evento em um servidor de banco de dados específico. O SQL Server nos fornece dois tipos principais de gatilhos:o DML Acionadores e o DDL gatilhos. Os gatilhos DDL serão acionados em resposta a diferentes eventos de linguagem de definição de dados (DDL), como a execução de instruções T-SQL CREATE, ALTER, DROP, GRANT, DENY e REVOKE. O gatilho DDL pode responder às ações DDL impedindo que essas alterações afetem o banco de dados, execute outra ação em resposta a essas ações DDL ou gravando essas alterações que são executadas no banco de dados.

O SQL Server DML Trigger é um tipo especial de procedimento armazenado projetado para executar uma sequência de ações em uma tabela de banco de dados, à qual o gatilho está anexado, quando um evento de linguagem de manipulação de dados (DML), como INSERT, UPDATE ou DELETE ação, ocorre para modificar o conteúdo das tabelas ou visualizações do banco de dados, independentemente de as linhas da tabela serem afetadas ou não. Os gatilhos diferem dos procedimentos armazenados em que os gatilhos são acionados automaticamente quando ocorre uma modificação de dados predefinida. Os gatilhos DML podem ser usados ​​para manter a integridade dos dados e reforçar as regras de negócios da empresa, assim como a funcionalidade de verificação de tabela e restrições de chaves estrangeiras, realizando processos de auditoria e outras ações pós-DML. Você pode usar os gatilhos DML para consultar outras tabelas e realizar consultas T-SQL complexas.

Se o gatilho for acionado, um tipo especial de tabelas virtuais chamadas Inseridas e Excluído serão usadas tabelas para manter os valores dos dados antes e depois da modificação. A instrução do gatilho funcionará no escopo da mesma transação que dispara esse gatilho. Isso significa que a transação não será confirmada completamente até que a instrução do gatilho seja concluída com êxito. Por outro lado, a transação será revertida se a instrução do gatilho falhar.

Existem dois tipos de acionadores DML:DEPOIS ou PARA acionar e EM VEZ DE acionar. O gatilho AFTER será acionado e executado após a execução da ação INSERT, UPDATE ou DELETE que o acionar com sucesso. Além disso, quaisquer ações de cascata referenciais e verificações de restrição devem ser bem-sucedidas antes de disparar o gatilho. O gatilho AFTER pode ser definido apenas no nível da tabela, sem a possibilidade de defini-lo nas visualizações. O gatilho INSTEAD OF é usado para substituir a instrução da ação que dispara o gatilho com a instrução fornecida no gatilho, revertendo essa instrução após gerar um erro quando alguém está tentando executar uma ação que quebra uma política específica, como atualizar uma coluna financeira crítica ou escrever a mudança em uma tabela de auditoria antes de realizar a mudança. O gatilho INSTEAD OF permite INSERT, UPDATE ou DELETE dados das views que referenciam dados de várias tabelas, além da possibilidade de rejeitar parte de uma consulta batch e executar outra parte desse batch com sucesso. O gatilho INSTEAD OF não pode ser usado com as visualizações atualizáveis ​​que possuem WITH CHECK OPTION e nas tabelas com um relacionamento referencial que especifica ações em cascata em DELETE ou UPDATE.

Depois de discutir os gatilhos teoricamente, vamos começar a mostrar o que discutimos na prática. Nas próximas demonstrações, mostraremos as diferentes situações em que podemos tirar proveito dos gatilhos do SQL Server.

APÓS… Acionador DML


Suponha que precisamos rastrear as ações DML que são executadas em uma tabela específica e gravar esses logs em uma tabela de histórico, onde o ID do registro inserido, atualizado ou excluído e a ação executada serão gravados na tabela de histórico. As instruções CREATE TABLE T-SQL abaixo podem ser usadas para criar as tabelas de origem e de histórico:
CREATE TABLE TriggerDemo_Parent
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO

CREATE TABLE TriggerDemo_History
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ParentID INT,
   PerformedAction VARCHAR (50),
  )
GO

Para rastrear a operação INSERT, criaremos um gatilho DML que será acionado após realizar uma operação INSERT na tabela pai. Este gatilho irá recuperar o último valor de ID inserido para essa tabela pai da tabela virtual inserida, como na instrução CREATE TRIGGER T-SQL abaixo:
CREATE TRIGGER AfterInsertTrigger
ON TriggerDemo_Parent
AFTER INSERT
AS
INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Insert')
GO

O rastreamento da operação DELETE pode ser obtido criando um gatilho DML que é acionado após a execução da operação DELETE na tabela pai. Novamente, o gatilho recuperará o valor de ID do último registro excluído dessa tabela pai da tabela virtual excluída, como na instrução CREATE TRIGGER T-SQL abaixo:
CREATE TRIGGER AfterDeleteTrigger
ON TriggerDemo_Parent
AFTER DELETE
AS
INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1  deleted.ID FROM deleted), 'Delete')
GO

Por fim, rastrearemos também a operação UPDATE criando um gatilho DML que será acionado após a execução de uma operação UPDATE na tabela pai. Dentro desta trigger, vamos recuperar o último valor de ID atualizado daquela tabela pai da tabela virtual inserida, levando em consideração que o processo UPDATE é realizado excluindo o registro e inserindo um novo registro com os valores atualizados, como no CREATE TRIGGER Instrução T-SQL abaixo:
CREATE TRIGGER AfterUPDATETrigger
ON TriggerDemo_Parent
AFTER UPDATE
AS
INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'UPDATE')
GO


As tabelas e os gatilhos estão prontos agora para nossos testes. Se você tentar inserir um novo registro na tabela pai usando a instrução INSERT INTO T-SQL abaixo:
INSERT INTO TriggerDemo_Parent VALUES ('AAA','BBB',500)

Então, verificando o plano de execução gerado pela execução da instrução INSERT anterior, você verá que duas operações de inserção serão executadas, afetando duas tabelas; a tabela pai com os valores especificados na instrução INSERT e a tabela de histórico devido ao acionamento do trigger AFTER INSERT, conforme plano de execução abaixo:



Também fica claro quando você verifica os dados inseridos nas tabelas pai e histórico usando as instruções SELECT abaixo:
SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Onde os valores especificados na instrução INSERT serão inseridos na tabela pai, e o log de inserção que contém o ID do registro inserido e a operação realizada será inserido na tabela de histórico, conforme resultado abaixo:



Agora, se você tentar atualizar um registro existente na tabela pai usando a instrução UPDATE T-SQL abaixo:
UPDATE TriggerDemo_Parent SET Emp_Salary=550 WHERE ID=1

E verifique o plano de execução gerado pela execução da instrução UPDATE anterior, você verá que a operação de atualização será seguida por uma operação de inserção afetando duas tabelas diferentes; a tabela pai será atualizada com o valor especificado na instrução UPDATE e a operação de inserção na tabela de histórico devido ao acionamento do gatilho AFTER UPDATE, conforme mostrado no plano de execução abaixo:



Verificando os registros da tabela pai e do histórico usando as instruções SELECT abaixo:
SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Você verá que a instrução de atualização modificará o valor Emp_Salary na tabela pai com o valor especificado na instrução UPDATE, e o log de atualização que contém o ID do registro atualizado e da operação realizada será inserido na tabela de histórico, conforme mostrado no resultado abaixo:



No último cenário do gatilho AFTER DML, rastrearemos a exclusão de um registro existente da tabela pai usando a instrução DELETE T-SQL abaixo:
DELETE FROM  TriggerDemo_Parent WHERE ID=1

Em seguida, verifique o plano de execução gerado pela execução da instrução DELETE anterior, você verá que a operação DELETE será seguida pela operação de inserção, afetando duas tabelas diferentes; a tabela pai da qual será excluído o registro com o ID fornecido na cláusula WHERE da instrução DELETE e a operação de inserção na tabela de histórico devido ao disparo do gatilho AFTER DELETE, conforme mostrado no plano de execução abaixo:



Se você verificar os registros da tabela pai e do histórico usando as instruções SELECT abaixo:
SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Você verá que o registro com o valor de ID igual a 1 foi excluído da tabela pai fornecida na instrução DELETE e o log de exclusão que contém o ID do registro excluído e a operação executada serão inseridos na tabela de histórico , como mostra o resultado abaixo:


EM VEZ DE… Acionador DML


O segundo tipo de gatilhos DML é o gatilho INSTEAD OF DML. Conforme mencionado anteriormente, o gatilho INSTEAD OF substituirá a instrução da ação que dispara o gatilho pela instrução fornecida no gatilho. Suponha que precisamos registrar as ações DML que os usuários estão tentando executar em uma tabela específica, sem permitir que eles executem essa ação. As instruções CREATE TABLE T-SQL abaixo podem ser usadas para criar as tabelas de origem e alternativas:
CREATE TABLE TriggerDemo_NewParent
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO


CREATE TABLE TriggerDemo_InsteadParent
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ParentID INT,
   PerformedAction VARCHAR (50),
  )
GO

Após criar as duas tabelas, inseriremos um único registro na tabela de origem para nossa demonstração usando a instrução INSERT INTO abaixo:
INSERT INTO TriggerDemo_NewParent VALUES ('AA','BB', 500)


Para esta demonstração, criaremos três gatilhos para substituir as operações INSERT, UPDATE e DELETE. O primeiro gatilho será usado para evitar qualquer operação de inserção na tabela pai e no log que mude para a tabela alternativa. O gatilho é criado usando a instrução CREATE TRIGGER T-SQL abaixo:
CREATE TRIGGER InsteadOfInsertTrigger
ON TriggerDemo_NewParent
INSTEAD OF INSERT
AS
INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Trying to Insert new ID')
GO

O segundo gatilho é usado para evitar qualquer operação de atualização na tabela pai e no log que se transforma na tabela alternativa. Este gatilho é criado como abaixo:
CREATE TRIGGER InsteadOfUpdateTrigger
ON TriggerDemo_NewParent
INSTEAD OF UPDATE
AS
INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Trying to Update an existing ID')
GO


O último gatilho será usado para evitar qualquer operação de exclusão na tabela pai e no log que mude para a tabela alternativa. Este gatilho é criado da seguinte forma:
CREATE TRIGGER InsteadOfDeleteTrigger
ON TriggerDemo_NewParent
INSTEAD OF DELETE
AS
INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Trying to Delete an existing ID')
GO

As duas tabelas e os três gatilhos estão prontos agora. Se você tentar inserir um novo valor na tabela pai usando a instrução INSERT INTO T-SQL abaixo:
INSERT INTO TriggerDemo_NewParent VALUES ('CCC','DDD',500)

Em seguida, verifique os registros da tabela pai e alternativa usando as instruções SELECT abaixo:
SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Devido ao fato de termos o gatilho INSTEAD OF INSERT na tabela pai, você verá pelo resultado que nenhum novo registro é inserido na tabela pai, e um log para a operação de inserção é inserido na tabela alternativa, conforme mostrado no resultado abaixo:



Tentando atualizar um registro existente na tabela pai usando a instrução UPDATE T-SQL abaixo:
UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Em seguida, verificando os registros da tabela pai e alternativa usando as instruções SELECT abaixo:
SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Você verá pelo resultado que o valor Emp_Salary do registro com o valor de ID igual a 1 da tabela pai não será alterado, e o log para a operação de atualização é inserido na tabela alternativa por ter o gatilho INSTEAD OF UPDATE na tabela pai, conforme mostrado no resultado abaixo:



Por fim, se tentarmos excluir um registro existente da tabela pai usando a instrução DELETE T-SQL abaixo:
DELETE FROM  TriggerDemo_NewParent  WHERE ID=1

E verifique os registros da tabela pai e alternativa usando as instruções SELECT abaixo:
SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Ficará claro a partir do resultado que o registro com o valor de ID igual a 1 da tabela pai não será excluído, e o log da operação de exclusão será inserido na tabela alternativa por ter o gatilho INSTEAD OF DELETE no pai tabela, como mostra o resultado abaixo:


DEPOIS… Acionador DML com mensagens


O gatilho AFTER também pode ser usado para gerar uma mensagem de aviso para um usuário. Nesse caso, a consulta será uma mensagem informativa que não impedirá a execução da instrução que dispara esse gatilho. Vamos descartar o gatilho INSTEAD OF UPDATE criado anteriormente e substituí-lo por outro gatilho AFTER UPDATE que gerará um erro de aviso após realizar qualquer operação de atualização usando as instruções T-SQL DROP/CREATE TRIGGER abaixo:
DROP TRIGGER InsteadOfUpdateTrigger
CREATE TRIGGER ReminderTrigger  
ON TriggerDemo_NewParent  
AFTER  UPDATE   
AS RAISERROR ('An Update is performed on the TriggerDemo_NewParent table', 16, 10);  
GO  

Se você tentar atualizar o valor Emp_Salary do funcionário com o valor de ID igual a 1 usando a instrução UDPATE abaixo:
UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Uma mensagem de erro será gerada nas Mensagens guia, que contém a mensagem fornecida no gatilho criado, conforme mostrado abaixo:



Verificando os dados da tabela pai usando a instrução SELECT abaixo:
SELECT * FROM TriggerDemo_NewParent

Você verá no resultado que o Emp_Salary foi atualizado com sucesso, conforme mostrado abaixo:



Se você precisar do gatilho AFTER UPDATE para interromper a operação de atualização após gerar a mensagem de erro, o ROLLBACK A instrução pode ser adicionada ao gatilho para reverter a operação de atualização que disparou esse gatilho, lembrando que o gatilho e a instrução que dispara o gatilho serão executados na mesma transação. Isso pode ser feito usando a instrução ALTER TRIGGER T-SQL, consulte:
ALTER TRIGGER ReminderTrigger  
ON TriggerDemo_NewParent  
AFTER  UPDATE   
AS RAISERROR ('An Update is performed on the TriggerDemo_NewParent table', 16, 10);  
ROLLBACK
GO  

Se você tentar atualizar o valor Emp_Salary do funcionário com o ID igual a 1 usando a instrução UPDATE abaixo:
UPDATE TriggerDemo_NewParent SET Emp_Salary=700 WHERE ID=1

Novamente, uma mensagem de erro será exibida nas Mensagens guia, mas desta vez, a operação de atualização será revertida completamente, conforme mostrado nas mensagens de erro abaixo:



Verificando o valor da tabela de origem usando a instrução SELECT abaixo:
SELECT * FROM TriggerDemo_NewParent

Você verá que o valor Emp_Salary não foi alterado, pois o gatilho AFTER UPDATE reverteu a transação geral após gerar a mensagem de erro, conforme mostrado no resultado da tabela abaixo:


Desvantagens do gatilho


Com todas as vantagens mencionadas dos gatilhos do SQL Server, os gatilhos aumentam a complexidade do banco de dados. Se o gatilho for mal projetado ou usado em excesso, isso levará a grandes problemas de desempenho, como sessões bloqueadas, devido ao prolongamento da vida útil da transação por mais tempo, sobrecarga extra no sistema devido à execução cada vez que um INSERT, UPDATE ou A ação DELETE é executada ou pode levar a problemas de perda de dados. Além disso, não é fácil visualizar e rastrear os gatilhos do banco de dados, especialmente se não houver documentação sobre isso, pois é invisível para os desenvolvedores e os aplicativos.

Alternativas de gatilho… Imponha a integridade


Se for constatado que os gatilhos estão prejudicando o desempenho de sua instância do SQL Server, você deverá substituí-los por outras soluções. Por exemplo, em vez de usar os gatilhos para impor a integridade da entidade, ela deve ser imposta no nível mais baixo usando as restrições PRIMARY KEY e UNIQUE. O mesmo é aplicado à integridade de domínio que deve ser imposta por meio de restrições CHECK e à integridade referencial que deve ser imposta por meio de restrições FOREIGN KEY. Você pode usar os gatilhos DML somente se os recursos suportados por uma restrição específica não puderem atender aos requisitos do seu aplicativo.

Vamos comparar entre impor a integridade do domínio usando gatilhos DML e usar as restrições CHECK. Suponha que precisamos forçar a inserção de valores positivos apenas na coluna Emp_Salary. Começaremos criando uma tabela simples usando a instrução CREATE TABLE T-SQL abaixo:
CREATE TABLE EmployeeSalaryTrigger
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO

Em seguida, defina o gatilho AFTER INSERT DML que garante que você insira um valor positivo na coluna Emp_Salary revertendo a transação se um usuário inserir um valor de salário negativo, usando a instrução CREATE TRIGGER T-SQL abaixo:
CREATE TRIGGER TRGR_EmployeeSalary ON EmployeeSalaryTrigger 
AFTER INSERT 
AS
DECLARE @EmpSal AS INT
SET @EmpSal = (SELECT TOP 1 inserted.Emp_Salary FROM inserted)
IF @EmpSal<0
BEGIN 
 RAISERROR  ('Cannot insert negative salary',16,10);
  ROLLBACK
END

Para fins de comparação, criaremos outra tabela simples, com o mesmo esquema, e definiremos uma restrição CHECK dentro da instrução CREATE TABLE para aceitar apenas valores positivos na coluna Emp_Salary, conforme mostrado abaixo:
CREATE TABLE EmployeeSalaryConstraint
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT CONSTRAINT EmpSal CHECK (Emp_Salary >=0)
  )
GO

Se você tentar inserir o registro abaixo que contém o valor Emp_Salary negativo na primeira tabela que possui um gatilho predefinido, usando a instrução INSERT INTO abaixo:
INSERT INTO EmployeeSalaryTrigger VALUES('Ali', 'Fadi',-4)
GO

A instrução INSERT falhará gerando uma mensagem de erro mostrando que você não pode inserir um valor negativo na coluna Emp_Salary e reverter a transação geral devido a ter um gatilho AFTER INSERT, conforme mostrado na mensagem de erro abaixo:



Além disso, se você tentar inserir o mesmo registro que contém um valor Emp_Salary negativo na segunda tabela que possui uma restrição CHECK predefinida usando a instrução INSERT INTO abaixo:
INSERT INTO EmployeeSalaryConstraint VALUES ('Ali', 'Fadi',-4)

A instrução INSERT falhará novamente mostrando que você está tentando inserir o valor que está em conflito com a condição de restrição CHECK, conforme mostrado na mensagem de erro abaixo:



A partir dos resultados anteriores, você vê que os métodos de restrição de gatilho e CHECK atingem a meta, impedindo que você insira valores Emp_Salary negativos. Mas qual é melhor? Vamos comparar o desempenho dos dois métodos verificando o peso do plano de execução para cada um. A partir dos planos de execução gerados após a execução das duas consultas, você verá que o peso do método acionador é três vezes o peso do método de restrição CHECK, conforme mostrado na comparação do plano de execução abaixo:



Além disso, para comparar o tempo de execução consumido por cada um, vamos executar cada um 1000 vezes usando as instruções T-SQL abaixo:
INSERT INTO EmployeeSalaryTrigger VALUES('Ali', 'Fadi',-4)
GO 10000  
INSERT INTO EmployeeSalaryConstraint VALUES ('Ali', 'Fadi',-4)
GO 10000 

Você verá que o primeiro método que está usando o acionador levará cerca de 31 ms para ser executado completamente, onde o segundo método que está usando a restrição CHECK levará apenas 17ms , que é cerca de 0,5 o tempo necessário no método usando o gatilho. Isso se deve ao fato de que o gatilho prolongará a vida útil da transação e reverterá a consulta que aciona o gatilho após executá-lo quando uma violação de integridade for encontrada, causando uma degradação de desempenho devido ao processo de reversão. O caso é diferente quando se utiliza a restrição CHECK, onde a restrição fará seu trabalho antes de fazer qualquer modificação nos dados, não necessitando de rollback em caso de violação.

Alternativas de gatilho… Auditoria


Como mencionamos anteriormente, os gatilhos também podem ser usados ​​para auditar e rastrear as alterações realizadas em uma tabela específica. Se esse método de auditoria causar uma degradação de desempenho em sua instância do SQL Server, você poderá substituí-lo facilmente pelo OUTPUT cláusula. A cláusula OUTPUT retorna informações sobre cada linha afetada pela operação INSERT, UPDATE ou DELETE, na forma de uma mensagem de confirmação ou um valor que pode ser inserido na tabela histórica. O método da cláusula OUTPUT também nos fornece mais controle sobre o código executado, pois ele será adicionado à própria instrução de inserção, modificação ou exclusão de dados sempre que desejar, ao contrário do gatilho que será sempre executado.

Vamos comparar entre registrar a inserção e modificação de dados na tabela de histórico usando gatilhos DML e usando a cláusula OUTPUT. Começaremos criando as tabelas de produção e de histórico abaixo usando a instrução CREATE TABLE T-SQL abaixo:
CREATE TABLE TriggerDemo_Prod
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO


CREATE TABLE TriggerDemo_ProdHistory
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ProdID INT,
   ProdSalary INT,
   TS DATETIME,
  )
GO

Depois que ambas as tabelas forem criadas com sucesso, criaremos o gatilho AFTER INSERT, UPDATE DML que gravará um registro na tabela de histórico se qualquer nova linha for inserida na tabela de produção ou um registro existente for modificado usando a instrução CREATE TRIGGER T-SQL abaixo de:
CREATE TRIGGER ProdHistory
ON TriggerDemo_Prod
AFTER INSERT, UPDATE
AS
INSERT INTO TriggerDemo_ProdHistory  VALUES ( (SELECT TOP 1  inserted.ID FROM inserted),(SELECT TOP 1  inserted.Emp_Salary FROM inserted), GETDATE())
GO

Para comparar o registro das alterações usando o método trigger e a cláusula OUTPUT, precisamos criar duas novas tabelas simples, as tabelas de produção e as tabelas de histórico, com o mesmo esquema das duas tabelas anteriores, mas desta vez sem definir um gatilho, usando o CREATE TABLE T-SQL instruções abaixo:
CREATE TABLE OutputDemo_Prod
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO


CREATE TABLE OutputDemo_ProdHistory
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ProdID INT,
   ProdSalary INT,
   TS DATETIME,
  )
  
GO

Agora as quatro tabelas estão prontas para o teste. Vamos inserir um registro na primeira tabela de produção que possui um gatilho usando a instrução INSERT INTO T-SQL abaixo:
INSERT INTO TriggerDemo_Prod values('AA','BB', 750)
GO 


Em seguida, inseriremos o mesmo registro na segunda tabela de produção usando a cláusula OUTPUT. A instrução INSERT INTO abaixo funcionará como duas instruções de inserção; a primeira inserirá o mesmo registro na tabela de produção e a segunda instrução de inserção ao lado da cláusula OUTPUT inserirá o log de inserção na tabela de histórico:
INSERT INTO OutputDemo_Prod  OUTPUT inserted.ID, inserted.Emp_Salary, GETDATE() 
INTO OutputDemo_ProdHistory	values('AA','BB', 750)
GO 

Verificando os dados inseridos nas quatro tabelas de produção e histórico, você verá que ambos os métodos, trigger e OUTPUT, escreverão o mesmo log na tabela de histórico com sucesso e da mesma forma, conforme mostrado no resultado abaixo:



A partir dos planos de execução gerados após a execução das duas consultas, você verá que o peso do método acionador é de aproximadamente (21%+36%) 57% do peso geral, onde o peso do método OUTPUT é de cerca de 43% , com pequena diferença de peso, conforme demonstrado na comparação dos planos de execução abaixo:



A diferença de desempenho é clara ao comparar o tempo de execução consumido por cada método, onde registrar as alterações usando o método de gatilho consumirá (114+125) 239ms para ser executado completamente, e o método que está usando o método da cláusula OUTPUT consome apenas 5ms , que é 2% do tempo usado no método de disparo, conforme mostrado claramente nas estatísticas de tempo abaixo:



Fica claro agora pelo resultado anterior que usar o método OUTPUT é melhor do que usar gatilhos para auditoria de alterações.

Links úteis:
  • CRIAR TRIGGER (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
  • Acionadores de DML https://docs.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers
  • Acionadores de DDL https://docs.microsoft.com/en-us/sql/relational-databases/triggers/ddl-triggers
  • Cláusula de SAÍDA (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql