SQL Server : 현재 세션에 대해서만 업데이트 트리거를 비활성화하는 방법은 무엇입니까?


15

SQL Server 2008 R2에서 일하고 있습니다.

tiu_benefit 이라는 AFTER INSERT, UPDATE 트리거 가있는 테이블 이점 이 있습니다 .

이 테이블에 대해 UPDATE 문을 작성하여 1 행을 업데이트하고 싶지만 트리거를 시작하고 싶지 않습니다. UPDATE 전에 트리거를 비활성화 한 다음 UPDATE 후에 트리거를 활성화 할 수 있다는 것을 알고 있습니다.

DISABLE TRIGGER tiu_benefit ON benefit;  
GO  
UPDATE benefit SET editor = 'srh' where benefit_id = 9876
GO
ENABLE TRIGGER tiu_benefit ON benefit;  
GO  

그러나이 비활성화 및 활성화 트리거는 현재 로그인 한 모든 사용자에게 영향을 미칩니다. 따라서 내 스크립트에서 트리거가 비활성화되어 다른 사용자가 UPDATE / INSERT를 실행할 가능성이 있습니다. 그렇기 때문에 현재 세션에 대해서만 트리거를 비활성화 및 활성화하고 싶습니다. 가능합니까? 그렇다면 어떻게 말하십시오.

감사


1
트리거를 수정할 수 없으면 대답은 '아니요'입니다.
jyao

답변:


6

나는 이것에 대해 약간의 테스트를했는데 단일 트랜잭션으로 프로세스를 실행하면 괜찮을 것이라고 생각합니다.

BEGIN TRANSACTION
GO

DISABLE TRIGGER tiu_benefit ON benefit;
GO

UPDATE benefit
SET editor = 'srh'
WHERE benefit_id = 9876
GO

ENABLE TRIGGER tiu_benefit ON benefit;
GO

--Decide to commit or rollback

--commit
--rollback 

내 테스트에서는 BEGIN TRANSACTIONDISABLE TRIGGER첫 번째 만을 강조 표시하고 실행했습니다 . 나는 다음 새 (두 번째) 쿼리 창을 열어 다양한 DML 문 (실행하려고 SELECT, INSERT, UPDATE DELETE기본 테이블에 대한 참조). 두 번째 쿼리 창에서 기본 테이블에 액세스하려는 모든 시도는 명시 적 트랜잭션이있는 창에서 보유한 잠금을 기다렸습니다. 명시 적 트랜잭션을 커밋 (또는 롤백)하면 두 번째 창에서 테이블에 액세스 할 수있었습니다.


이것은 작동하지만 트랜잭션을 열린 상태로 유지하는 시간에 따라 잠금으로 인해 다운 스트림에서 의도하지 않은 문제가 발생할 수 있습니다.
CaM

@CaM-OP가 커밋하거나 트랜잭션을 빠르게 롤백한다고 가정하면 한 행 업데이트가 너무 오래 걸리지 않을 것이라고 가정합니다. 다행히도 benefit_id:)에 대한 색인이 있습니다 :
Scott Hodgin

트리거를 변경할 필요가
없기

18

문제를 해결하려면 문제에 대한 프로그래밍 방식을 취해야합니다. 여기에 갈 수있는 두 가지 경로가 있습니다. 이러한 접근 방식이 필요한 이유는 특정 명령문에 대한 트리거를 비활성화 할 수 없기 때문에 테이블 전체에 대해서만 비활성화 할 수 있기 때문입니다.

옵션 1 : Context_Info ()

MS SQL 팁의 Samuel Vanga 는 훌륭한 예입니다.

USE AdventureWorks; 
GO 
-- creating the table in AdventureWorks database 
IF OBJECT_ID('dbo.Table1') IS NOT NULL 
DROP TABLE dbo.Table1 
GO 
CREATE TABLE dbo.Table1(ID INT) 
GO 
-- Creating a trigger 
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE 
AS 
DECLARE @Cinfo VARBINARY(128) 
SELECT @Cinfo = Context_Info() 
IF @Cinfo = 0x55555 
RETURN 
PRINT 'Trigger Executed' 
-- Actual code goes here 
-- For simplicity, I did not include any code 
GO

이제 Samuel은 트리거가 실행되기를 원하지 않을 때 다음을 사용합니다.

SET Context_Info 0x55555 
INSERT dbo.Table1 VALUES(100)

Context_Info 다음 시스템보기를 사용하여 현재 세션에 관한 정보를 가져옵니다.

  • sys.dm_exec_requests

  • sys.dm_exec_sessions

  • sys.sysprocesses

여기서 이데올로기는 설정하는 이진 문자열이 현재 세션에만 노출되므로 세션 중에 트리거가 실행될 때 Context_info함수 의 범위 및 변수 설정 이 표시되고 트리거의 이스케이프 부분으로 이동합니다. 대신에.

옵션 2 : 온도 테이블

Itzik 벤의 GaN훌륭한 솔루션 그의 나중에 책에서 또한 그의 책 "T-SQL 프로그래밍 내부 마이크로 소프트 SQL 서버 2008 T-SQL 프로그래밍"에서 T-SQL 쿼리를 . 이 context_info기능에 대한 주요 문제점 은 사소한 TempDB 오버 헤드입니다.

놀람을 망치고 책의 음모를 망치지 않기 위해 (나는 그들이 구입할 가치가 있다고 느꼈다), 당신은 방아쇠를 바꿀 것이다.

트리거는 임시 테이블을 확인해야합니다. 임시 테이블이 존재하면 트리거는 종료를 알고 조치를 수행하지 않아야합니다.

수행하려는 업데이트 명령문에서 임시 테이블을 먼저 작성하십시오. 트리거와 동일한 트랜잭션에서 표시되며 트리거로 인해 명령문이 무시됩니다.

트리거 예 :

CREATE TRIGGER TRIGGERNAME ON TABLENAME for INSERT AS

IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
GO

트리거를 실행하지 않으려는 시작 명령문의 예 :

CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);

당신의 예를 위해 그것을 모두 넣는 것 :

ALTER TRIGGER tiu_benefit ON benefit FOR 
... 
AS
...
IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
--... rest of code here
GO

CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);
UPDATE benefit SET editor = 'srh' where benefit_id = 9876;
GO

2
트리거에서 임시 테이블 대신 context_info ()를 사용합니다. 다시 말해, 트리거가 context_info가 특정 값을 반환 함을 감지하면 그에 따라 트리거가 작동합니다. 관련 SO 질문을 여기에서 참조하십시오 : stackoverflow.com/questions/3025662/…
jyao

1
특정 사람이 방아쇠를 쳤을 때 방아쇠가 절대로 작동하지 않도록 지시 context_info하는 데 사용 original_login()하는 것과 유사한 검사를 수행 할 수도 있습니다.
케네스 피셔

2

나는 하나 CONTEXT_INFO이상 을 사용합니다 SESSION_CONTEXT. 둘 다 세션 기반 값입니다.

로컬 임시 테이블 옵션 및 심지어 비활성화 / 활성화 트리거 옵션과 관련하여 고려해야 할 사항 : 둘 다 일정량의 잠금 및 전송 로그 활동이 필요합니다. 이 두 가지 옵션 모두 최소한이라도 경합 가능성을 높입니다. 두 개의 "컨텍스트"옵션은 더 가벼우 며 메모리 전용이어야합니다.


context_info는 진통제입니다. 프로덕션 데이터 변경을 실행할 때마다 편리합니다. 특히 트리거를 비활성화하면 다른 작업이 트리거를 발생시키지 않을 수 있습니다.
Biju jose
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.