Trigger_6
12 Ocak 2017 Perşembe
Trigger'ları doğru yerde ve zamanda kullandığınızda emin olun birçok işinizi çözecektir. SQL Server'da siyah ve beyaz tonlar(konu başlıkları) vardır bana göre trigger konusu bu ikisi arasında kalan gri bölgede yer alıyor. İfrat ve tefrit durumlarını iyi ayarlamak gerekiyor dolayısıyla.
WITH ENCRYPTION
View ve SP'ler gibi trigger'larda şifrelenip başkaları tarafından görülmesi engellenebilir. Özellikle ticari bir yazılım geliştiriyorsanız, güvenliğe önem veriyorsanız ya da kullanıcıların değiştirdiğiniz verinin ne olduğunu görmesini istemiyorsanız, bu özellik kullanışlıdır. Ancak böyle bir durum için, trigger'ınızın bir kopyasını farklı bir yerde barındırmakta fayda var.
Şifrelenmiş nesneler sys.sql_modules katoloğunda da görülmez. Bu view'e SELECT attığınızda "definition" sütununun NULL olduğunu göreceksiniz.
ÇALIŞMA MANTIĞI
Trigger'ların çalışma mantığını anlamak istiyor isek evvela 2 sözde tabloyu yani inserted ve deleted tabloları anlamakla işe başlamalıyız. Bu tabloların her ikisi de ana tabloyla(base table) eşdeğer alanlara sahiptirler ve mantıksal bir tablo şeklinde RAM'de tutulurlar. Siz ana tablo'ya bir kayıt eklediğinizde o kayıt inserted tablosuna da eklenir ya da tablodan bir kayıt sildiğinizde o kayıt deleted tablosuna eklenir. Deleted tablosunu inserted tablosundan ayıran bir fark vardır. Silinmiş kayıtlar sadece deleted'da bulunur, gerçek tablodan artık silinmiştir. Ancak transaction henüz kapatılmadığı için istenmeyen bir durumu trigger'ın ROLLBACK yapması sağlanabilir. Update işleminde ise mantık olarak önce kaydın silinmesi(deleted) ve sonra da kaydın eklenmesi(inserted) durumu hâsıl olduğu için bu işlem için ayrıca bir updated tablosu bulunmaz.
Şayet bir transaction 10 adet kayıt ekliyor ise bu on kayıt için trigger ayrı ayrı devreye girmez. Bir seferde devreye girer zira SQL Server satır bazlı trigger desteği vermez.
Not: CREATE TRIGGER ifadesini çalıştırabilmek için sysadmin, db_owner veya db_dlladmin sistem rolüne sahip olmak gerekir. Şayet oluşturulan trigger'ın uzantısı farklı bir tabloya gidiyor ise bu tabloya da aynı şekilde trigger sahibinin erişim izni olması gerekir.
Not: Bir tablo üstünde hangi trigger'ların tanımlandığını öğrenmek için, sp_helptrigger tablo_adı, trigger'ın kodlarını görebilmek için sp_helptext trigger_adı, bir trigger'ın hangi tabloların hangi alanlarına etki ettiğini öğrenmek için, sp_depends trigger_adı şeklindeki SP'leri kullanmalısınız.
Önemli Not: INSERTED ve DELETED sözde(pseudo) tabloları transaction log'larından beslenirler. Dolayısıyla TRUNCATE TABLE gibi loglara yansımayan değişiklikler, trigger tarafından yakalanamaz.
Önemli Not: INSTEAD OF trigger'larda constraint'ler kontrol edilmeden önce bu tablolar oluşturulur, FOR trigger'larda ise constraint'ler kontrol edildikten sonra tablolar oluşturulur.
Önemli Not: Trigger'lar geçici tablolar üzerinde oluşturulamazlar fakat bunlara referans gösterebilirler.
VERİ BÜTÜNLÜĞÜ KURALI İÇİN TRIGGER KULLANILMASI
Trigger'lar check constraint ile, hatta default ile aynı işlevselliğe sahip olabilir. Trigger'larmı, check constraint'lermi kullanmalıyım sorusunun cevabı duruma bağlı olacaktır. Check constraint aynı işi yapabiliyorsa ilk tercih olmalıdır. Bununla birlikte, check constraint'in trigger'ın yaptığı işi yapamadığı ya da istenildiği gibi yapamadığı zamanlar vardır. Check constraint yerine trigger kullanmak isteyeceğiniz durumlar şunlar olabilir:
* Ayrı ayrı tablolardaki verilere başvurulması gerektiğinde,
* Güncellemelerde delta(güncelleme öncesi ve sonrası arasındaki farklılıklar) kontrolü gerektiğinde,
* Özel hata mesajları belirlemek istediğinizde.
Önemli Not: Constraint'ler transaction bloğundan önce çalışırlar.
Trigger'ları başlatan ifadeler, bir transaction(her ne kadar açıkça BEGIN TRAN kullanılmasada)'ın parçasıdır. Bir trigger'ın başlatılmasıyla, tüm sorgu çalışır ve transaction log bilgisi tutulur.(tutulan log bilgisi trigger'ın başladığı noktaya kadar tutulur!) Şayet, trigger'ın geri alma(rollback) işlemi yapması gerekirse, yapılmış olan tonlarca işin de geri alınması durumu ortaya çıkar dolayısıyla bu'da performansa aşırı bir yük bindirir. Bu performans yavaşlamasının etkisi, sorgunuzun büyüklüğü ile alakalı bir durumdur. Constraint tarafına baktığımızda, ifadelerin transaction bloğundan önce çalıştığını görüyoruz. Yani koşulunuza uyan veya uymayan durumlar önceden bellidir. İşte bu durum constraint'lerin trigger'lara nazaran daha hızlı çalışması durumunu garanti ediyor.
IF UPDATE() VE COLUMNS_UPDATED() YAPILARI
Update() fonksiyonu sadece trigger çalışma alanı ile ilgilidir. Bu fonksiyonun amacı, belirli bir sütunun güncellenip güncellenmediğini gösteren bir Boolean(true-false) değeri sağlamaktır. Belirli bir kod bloğunun çalıştırılıp çalıştırılmayacağına karar vermek için bu fonksiyonu kullanabilirsiniz. Örneğin, bir kod sadece belirli bir sütun güncellendiğinde çalıştırılacaksa bu fonksiyonu kullanarak karar verebilirsiniz.
Kullanım şekli:
CREATE TRIGGER trigger_adı
ON tablo_adı
FOR UPDATE [,DELETE, INSERT]
AS
IF UPDATE(sütun_ismi_1) OR UPDATE(sütun_ismi_2)
BEGIN
kod bloğu
END
Columns_updated() fonksiyonu update() fonksiyonundan biraz farklı çalışır fakat aynı amaca hizmet eder. Columns_updated() fonksiyonu bir seferde birden fazla sütunu kontrol etmemizi sağlar. Bunun için, bir yada daha fazla byte değerindeki varbinary verideki her bit, tablodaki belirli bir sütunu ifade edecek şekilde bir bit maskesi kullanılarak maskelenir.
Kullanım şekli:
CREATE TRIGGER trigger_adı
ON tablo_adı
FOR UPDATE [,DELETE, INSERT]
AS
IF COLUMNS_UPDATED() & maske değer > 0
BEGIN
kod bloğu
END
İÇ İÇE TRIGGER'LAR(Nested Trigger)
İç içe yerleştirilen trigger'lar bir ifade sonucu değil başka bir trigger'ın çalışması sonucu tetiklenirler. Bu tip trigger'lar 32 seviyeye(iç içe yerleştirme sınırı) kadar birbirlerini desteklerler. Daha fazla tetiklenme seviyesi desteklenmez. Bu sebepten, iç içe trigger'lar tanımlanırken, herhangi bir anda trigger'ın kaçıncı seviyeden çağrıldığını anlamak için şu ifadeye başvurabiliriz:
SELECT TRIGGER_NESTLEVEL(object_id('[urunFiyatAzalmasin]'))
@@NESTLEVEL fonksiyonu da aynı işi görür.
İç içe yerleştirme zincirinde herhangi bir yerde rollback işlemi yapılırsa tümüyle zincir geri alınır. Diğer bir deyişle iç içe yerleştirilmiş trigger'lar zinciri bütünüyle transaction gibi davranır.
SQL Server'ın iç içe trigger çalıştırma özelliğini kapatmak için:
sp_configure 'nested triggers', 0
RECURSIVE TRIGGER'LAR
Bir trigger'ın yaptığı işlem, aynı trigger'ın tekrar başlamasına neden olduğunda bu trigger recursive olarak adlandırılır. Bu tip trigger'lar varsayılan olarak aktif değildirler. Yani bir update trigger'ı tekrar tekrar çalışmaz, yalnızca bir kez çalışır. Bu durumu veritabanı seçeneklerinden tersine çevirmek mümkündür. RECURSIVE_TRIGGERS seçeneğini aktif hale getirmemiz gerekir, bunun için yazım şekli:
ALTER DATABASE veritabanı_adı
SET RECURSIVE_TRIGGERS ON
ya da
sp_dboptions veritabanı_ismi, 'recursive_triggers', True