Tetikleyicileri kullanmadan SQL Server'da bir sorgu tetikleyen istemcinin kimliğini bulun?


11

Şu anda veri değişikliklerini izlemek için Veri Yakalamayı Değiştir (CDC) kullanıyorum ve değişiklikleri yapan sorguyu gönderen istemcinin ana bilgisayar adını ve IP adresini izlemek istiyorum. Aynı kullanıcı adı ile oturum açmış 5 farklı istemci varsa, biri 5'in hangi sorguyu tetiklediğini izleme muamelesi ile karşı karşıya kalır. Bulduğum diğer değerli çözümler arasında CDC tablosunun aşağıdaki komutla değiştirilmesi yer alıyor:

ALTER TABLE cdc.schema_table_CT 
ADD HostName nvarchar(50) NULL DEFAULT(HOST_NAME())

Ancak bu, sorguyu tetikleyen sunucunun ana bilgisayar adını döndürür, sorguyu tetikleyen istemcinin ana bilgisayar adını döndürmez.

Bu sorunun etrafında bir yol var mı? İstemcinin ana bilgisayar adını veya IP adresini (veya başka bir tür benzersiz kimliği) günlüğe kaydetmeye yardımcı olacak bir şey. Tetikleyicileri kullanmak istemiyorum, çünkü sistemi yavaşlatıyor, CDC sistem tabloları da oluşturuyor, bu yüzden görünüşe göre mümkün olmayan bir tetikleyici var.

Yanıtlar:


4

CDC hakkında emin değilim, ancak giriş varsa view server state permissionbazı bilgiler almak için DMV kullanabilirsiniz.

Bu, burada Çevrimiçi Kitaplar'da verilmektedir . Sorguyu size verecek sütunları eklemek için değiştirdim IP address:

SELECT 
    c.session_id, c.net_transport, c.encrypt_option, c.auth_scheme,
    s.host_name, s.program_name, s.client_interface_name,
    c.local_net_address, c.client_net_address, s.login_name, s.nt_domain, 
    s.nt_user_name, s.original_login_name, c.connect_time, s.login_time 
FROM sys.dm_exec_connections AS c
JOIN sys.dm_exec_sessions AS s
    ON c.session_id = s.session_id
WHERE c.session_id = SPID;  --session ID you want to track

4

"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_INFOOperasyon 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 ContextInfosü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 SUBSTRINGve 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 INSERTbirinde yapıldığı gibi) depolamak daha hızlı olabilir ve yalnızca bir SELECTihtiyacınız olduğunda.

Tüm aramalarımı SUBSTRINGve CONVERTçağrıları, CROSS APPLYgerektiğ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_INFOyalnı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_INFOve 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 FUNCTIONhareketsizdir (a'nın etrafında bir numara kullanabilirsiniz) VIEW, ancak yapmam ).

Ayrıca, SET CONTEXT_INFOkendisini 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 ClientHostunsuru 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 INSERTtavsiye 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 JOINde buna gelecekteki sorgular (veya FUNCTIONzaman 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

3

Lütfen bağlantı hatasına bir göz atın : Aşağıda ilgili pasaj

Bu davranış tasarım gereğidir. CDC, bir değişiklikle ilgili aşağıdaki bilgileri göstermek üzere tasarlanmıştır: güncellenmiş sütunlar, işlem türü ve işlem bilgileri. Bir denetim çözümü olarak tasarlanmamıştır. Toplam ETL süresini azaltmak için anahtar olan artımlı veri yükü aracılığıyla verimli Ekstrakt Transferi ve Yük çözümlerini (ETL) sağlamak için oluşturulmuştur. Ana hedefi kim ne zaman değil, "ne değişti" ifşa olduğunu ... Bunun için SQL Denetim özelliği tavsiye.

Şu an itibariyle CDC'yi bir Denetim çözümünde dönüştürmenin bir planı yok.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.