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
トリガーを変更できない場合、答えはノーです。
チャオ

回答:


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最初のもののみを強調表示して実行しました。私は、新しい(第2)クエリウィンドウを開いて、さまざまなDML文(実行しようとしたSELECTINSERTUPDATE DELETEベーステーブルに対して)を。2番目のクエリウィンドウでベーステーブルにアクセスするすべての試みは、明示的なトランザクションでウィンドウが保持するロックを待機していました。明示的なトランザクションをコミット(またはロールバック)すると、2番目のウィンドウはテーブルにアクセスできました。


これは機能しますが、トランザクションを開いておく期間によっては、ロックがダウンストリームで意図しない問題を引き起こす可能性があります。
CaM

@CaM-OPがトランザクションをすばやくコミットまたはロールバックすると仮定すると、1行の更新にそれほど時間がかからないと想定します。うまくいけば、次のインデックスがありますbenefit_id:)
スコットホジン

トリガーに変更を加える必要がないので、このソリューションが本当に好きでした
-srh

18

あなたの問題を解決するために、私たちは問題に対してプログラム的なアプローチをとる必要があります。ここには2つのルートがあります。これらのアプローチが必要な理由は、特定のステートメントのトリガーを無効にすることはできず、テーブル全体に対してのみ無効にできるためです。

オプション1:Context_Info()

MS SQL Tipsの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

サミュエルがトリガーの実行を望まない場合、これを使用します。

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 Ben-Ganは、彼の著書「Microsoft SQL Server 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単一のVARBINARY(128)値です。これは少なくともSQL Server 2000以降で利用可能CONTEXT_INFOです。DMVによってVIEW SERVER STATE返されるフィールドなので、誰でも表示できますsys.dm_exec_sessions。私は以前にこれを使用しましたが、非常にうまく機能します。

    SET CONTEXT_INFO経由で設定CONTEXT_INFO()またはsys.dm_exec_sessions
    経由で取得

    に保存する値のタイプに応じて、CONTEXT_INFO注意すべきいくつかのニュアンスがあります。これについては、次のブログ投稿で説明します。

    CONTEXT_INFO()がSET CONTEXT_INFOによって設定された正確な値を返さないのはなぜですか?

  • Session_contextは、値のキー/値ペアSQL_VARIANTです。これはSQL Server 2016で導入されました。さまざまな目的のための値の分離は非常に便利です。Session_contextは、現在のセッションでのみ表示可能です。

    sp_set_session_contextを介してこの値を設定しますSESSION_CONTEXTを
    介してこの値を取得します

ローカルテンポラリテーブルオプション、さらにトリガーの無効化/有効化オプションに関して考慮する必要があること:両方とも、ある程度のロックとtran logアクティビティが必要です。これらのオプションはどちらも、たとえ最小限であっても、競合の可能性を高めます。2つの「コンテキスト」オプションは、より軽量/メモリのみにする必要があります。


context_infoは、本番データの変更を実行する場合に便利です。特にトリガーを無効にすると、他の操作がトリガーを起動しない可能性があります。
ビジュホセ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.