So identifizieren Sie datenbankübergreifende Abfragen in SQL Server

7

In Vorbereitung auf ein Migrationsprojekt versuchen wir, alle Abfragen zu identifizieren, die Daten über Datenbanken hinweg auswählen.

Dies kann folgende Form haben:

SELECT fieldA, fieldB
FROM dbo.TableA a
JOIN DatabaseB.dbo.TableB b ON b.ID = a.ID

oder

DECLARE @resultFromDatabaseB VARCHAR(50)

SELECT @resultFromDatabaseB = b.ID
FROM DatabaseB.dbo.TableB

SELECT fieldA, fieldB
FROM dbo.TableA a
WHERE a.ID = @resultFromDatabaseB

oder jede andere Variante (einschließlich INSERTS / UPDATES / etc ...)

Leider sind die meisten Abfragen keine gespeicherten Prozeduren, sodass ich keine statische Analyse des SQL-Textes durchführen kann. Mein aktueller Plan sieht vor, den zwischengespeicherten Abfragetext aufzuzeichnen und statisch zu analysieren.

Gibt es Alternativen zu diesem Ansatz? dh: Verwendung von erweiterten Ereignissen / Trace / Audit?

Andrew Bickerton
quelle

Antworten:

3

Ich würde eine Sitzung für erweiterte Ereignisse einrichten, um erfasste Ereignisse zu erfassen und die Ereignisse mit der API zu streamen.

Zuallererst die Sitzung:

CREATE EVENT SESSION crossdb ON SERVER 
ADD EVENT sqlserver.lock_acquired(
    SET collect_database_name=(1),collect_resource_description=(1)
    ACTION(
        sqlserver.request_id,sqlserver.session_id,
        sqlserver.sql_text,sqlserver.tsql_frame
    )
    WHERE (
            [package0].[equal_boolean]([sqlserver].[is_system], (0)) -- user SPID
        AND [package0].[equal_uint64]([resource_type], (5)) -- OBJECT
        AND [package0].[not_equal_uint64]([database_id], (32767))  -- resourcedb
        AND [package0].[greater_than_uint64]([database_id], (4)) -- user database
        AND [package0].[greater_than_equal_int64]([object_id], (245575913)) -- user object
        AND (
               [mode] = (1) -- SCH-S
            OR [mode] = (6) -- IS
            OR [mode] = (8) -- IX
            OR [mode] = (3) -- S
            OR [mode] = (5) -- X
        )
        AND [database_name] <> N'distribution'
    )
)
WITH (
    MAX_MEMORY=4096 KB,
    EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
    MAX_DISPATCH_LATENCY=30 SECONDS,
    MAX_EVENT_SIZE=0 KB,
    MEMORY_PARTITION_MODE=NONE,
    TRACK_CAUSALITY=OFF,
    STARTUP_STATE=OFF
)
GO

Dann können Sie die Ereignisse auf transaction_idund gruppieren tsql_frame. Die Gruppen, die mehr als eine berühren database_id, geben datenbankübergreifende Anweisungen aus. Anschließend können Sie die Anweisung aus dem Extrakt sql_textAktion, mit der offsetStartund offsetEndaus tsql_frame.

Geben Sie hier die Bildbeschreibung ein

Ich habe ein ähnliches Beispiel in meinem Blog hier: https://spaghettidba.com/2015/04/20/tracking-table-usage-and-identifying-unused-objects/

spaghettidba
quelle
Da dies für SQL 2008R2 gilt, ist die Aktion sqlserver.tsql_frame nicht verfügbar. Ich muss auch das, was erfasst wird, um den Namen der Clientanwendung und den Client-Server erweitern.
Andrew Bickerton
Sie benötigen den tsql_frame nur, wenn Sie ihn auf Anweisungsebene aufschlüsseln müssen, aber auf Stapelebene sind Sie wahrscheinlich in Ordnung. Anwendungsname und Hostname sollten in 2008R2 verfügbare Aktionen sein, aber ich habe keine Instanz zum Testen, sorry
spaghettidba
danke, ich werde deine Antwort bearbeiten, um diese Unterschiede zu berücksichtigen (sobald ich sie getestet habe) - danke :-)
Andrew Bickerton