"Tetikleyicileri kullanmadan" derken, tablolarda herhangi bir tetikleyici mi yoksa sadece satır satır tetikleyici mi demek istediniz ?
Eğer Soruyorum çünkü edebilir Eğer akıllıca kullanımı ile istediklerini elde edebilmek CONTEXT_INFO()
fonksiyonu, ancak emin olmak gerekir SET CONTEXT_INFO
Operasyon gerçekleşecek doğru önce çağrıldı.
Bunu yapmak için bir yer, sunucu düzeyinde bir oturum açma tetikleyicisi olabilir (yani veritabanı / nesne düzeyinde bir tetikleyici değil), şöyle:
USE master
GO
CREATE TRIGGER tr_audit_login
ON ALL SERVER
WITH EXECUTE AS 'sa'
AFTER LOGON
AS BEGIN
BEGIN TRY
DECLARE @eventdata XML = EVENTDATA();
IF @eventdata IS NOT NULL BEGIN
DECLARE @spid INT;
DECLARE @client_host VARCHAR(64);
SET @client_host = @eventdata.value('(/EVENT_INSTANCE/ClientHost)[1]', 'VARCHAR(64)');
SET @spid = @eventdata.value('(/EVENT_INSTANCE/SPID)[1]', 'INT');
-- pack the required data into the context data binary
-- (spid is just an example of packing multiple data items in a single field: you would probably use @@SPID at the point of use, instead)
DECLARE @context_data VARBINARY(128);
SET @context_data = CONVERT(VARBINARY(4), @spid)
+ CONVERT(VARBINARY(64), @client_host);
-- persist the spid and host into session-level memory
SET CONTEXT_INFO @context_data;
END
END TRY
BEGIN CATCH
/* do better error handling here...
* logon trigger can lock all users out of server, so i am just swallowing everything
*/
DECLARE @msg NVARCHAR(4000) = ERROR_MESSAGE();
RAISERROR('%s', 10, 1, @msg) WITH LOG;
END CATCH
END
Daha sonra bağlamı saklamak için tablonuza varsayılan kısıtlama ekleyebilirsiniz (ekleme hızı için):
ALTER TABLE cdc.schema_table_CT
ADD ContextInfo varbinary(128) NULL DEFAULT(CONTEXT_INFO())
Bunu yaptıktan sonra, bu ContextInfo
sütunu biraz dilim ve zar ile sorgulayabilirsiniz :
SELECT *
,spid = CONVERT(INT, SUBSTRING(ContextInfo, 1, 4))
,client = CONVERT(VARCHAR(64), SUBSTRING(ContextInfo, 5, 64))
FROM cdc.schema_table_CT
Teknik olarak, bunu SUBSTRING
ve CONVERT
şeyleri varsayılan kısıtlamanızın bir parçası olarak yapabilir ve istemci IP'sini orada depolayabilirsiniz, ancak tüm içeriği orada (her INSERT
birinde yapıldığı gibi) depolamak daha hızlı olabilir ve yalnızca bir SELECT
ihtiyacınız olduğunda.
Tüm aramalarımı SUBSTRING
ve CONVERT
çağrıları, CROSS APPLY
gerektiğinde yapacağım tek sıralı satır içi tablo değerli bir işleve sarmaya meyilli olabilirim . Bu, açma mantığını tek bir yerde tutar:
CREATE FUNCTION fn_context (
@context_info VARBINARY(128)
)
RETURNS TABLE
AS RETURN (
SELECT
spid = CONVERT(INT, SUBSTRING(@context_info, 1, 4))
,client = CONVERT(VARCHAR(64), SUBSTRING(@context_info, 5, 64))
)
GO
SELECT *
FROM cdc.schema_table_CT s
CROSS APPLY dbo.fn_context(s.ContextInfo) c
Bunun CONTEXT_INFO
yalnızca 128 bayt olduğunu unutmayın VARBINARY
. 128 bayta sığabileceğinden daha fazla veriye ihtiyacınız varsa, tüm bu verileri tutmak için bir tablo oluşturur, oturum açma tetikleyicisindeki tabloya bu 'oturum' için satır olarak ekler CONTEXT_INFO
ve o tablonun yedek anahtar değerine ayarlanır
Ayrıca, yalnızca varsayılan bir kısıtlama olduğu için, uygun şekilde ayrıcalıklı bir kullanıcının istirahat tablosundaki bağlam verilerinin üzerine yazmasının önemsiz olduğunu unutmayın. Elbette, aynı şey 'denetim' tarzı tablolardaki diğer tüm sütunlar için de geçerlidir.
Bir varsayılandan ziyade kalıcı bir hesaplanmış sütun olabilirse iyi olurdu, ancak CONTEXT_INFO()
işlev deterministik değildir, bu yüzden FUNCTION
hareketsizdir (a'nın etrafında bir numara kullanabilirsiniz) VIEW
, ancak yapmam ).
Ayrıca, SET CONTEXT_INFO
kendisini aramak ve gününüzü karıştırmak için yeterli erişime sahip olan (örneğin sahte değerler veya özel hazırlanmış depolanmış enjeksiyon ile), bu nedenle içeriği şüphe ve özenle ele alın, görüntülemeden önce kodlayın ve istisnaları ele alın. iyi.
Hostname gelince, bence ClientHost
unsuru EVENTDATA()
size IP adresini (veya verir <local machine>
göstergesi). Teknik olarak geri ana makine adına ters DNS aramalarını yapmak CLR kullanabilirsiniz olsa da, bu her için yapmak çok yavaş olma eğilimi INSERT
tavsiye ederim bu yüzden, değil bunu yapmak için.
Eğer varsa sahip bir hostname olması, periyodik olarak yerel DHCP sunucusu veya DNS bölge dosyasından mevcut kiralama ayrı tablo doldurmak için bir çıkış bant dışı bir süreç olarak, bir SQL Agent işi kullanmak istiyor ve belki LEFT JOIN
de buna gelecekteki sorgular (veya FUNCTION
zaman içinde nokta için varsayılan bir kısıtlamaya değer sağlamak için bir skaler sarın ).
Yine, uygulamanın herkese açık bir bileşeni varsa, IP adreslerinin ve ana bilgisayar adlarının güvenilir olmadığını (örn. NAT nedeniyle) unutmayın. Halka açık olmasa bile, çoğu IP / ana bilgisayar adı eşlemesinde, etmen yapmanız gerekebilecek belirli bir zamana dayalı bileşen vardır.
Son olarak, giriş tetikleyicinizi uygulamadan önce, sunucunuzun özel yönetici bağlantısını açmanız faydalı olabilir. Oturum açma tetikleyicisi herhangi bir şekilde bozulursa, tüm kullanıcıların oturum açmasını engelleyebilir (sysadmin hesapları dahil):
USE master
GO
-- you may want to do this, so you have a back-out if the login trigger breaks login
EXEC sp_configure 'remote admin connections', 1
GO
RECONFIGURE
GO
Kilitlenirseniz, DAC oturum açma tetikleyicisini bırakmak veya devre dışı bırakmak için kullanılabilir:
C:\> sqlcmd -S localhost -d master -A
1> DISABLE TRIGGER tr_audit_login ON ALL SERVER
2> GO