Jak odfiltrować wykorzystanie funkcji skalarnej wartości zdefiniowanej przez użytkownika z danych audytu programu SQL Server?


12

Mamy bazę danych SQL Server, która ma specyfikację kontroli bazy danych, która kontroluje wszystkie działania wykonywane w bazie danych.

CREATE DATABASE AUDIT SPECIFICATION [dbAudit]
FOR SERVER AUDIT [servAudit]
ADD (EXECUTE ON DATABASE::[DatabaseName] BY [public])

Odkryliśmy, że niektóre zapytania zapisują w dzienniku kontroli użycie funkcji skalarnej dla każdego wiersza w zestawie wyników. Kiedy tak się dzieje, dziennik zapełnia się, zanim będziemy mogli go ETL umieścić w ostatecznym miejscu spoczynku i mamy luki w logowaniu.

Niestety z powodów zgodności nie możemy po prostu przestać sprawdzać każdego EXECUTEoświadczenia.

Naszym pierwszym podejściem do rozwiązania tego problemu jest użycie WHEREklauzuli dotyczącej Audytu serwera w celu odfiltrowania działania. Kod wyglądał następująco:

WHERE [object_id] not in (Select object_id from sys.objects where type = 'FN' )

Niestety, SQL Server nie zezwala na relacyjny operator IN (prawdopodobnie dlatego, że nie chce zapytać za każdym razem, gdy musi zapisywać w dzienniku kontroli).

Chcielibyśmy uniknąć zapisywania przechowywanego proc, który koduje na stałe object_idw WHEREklauzuli, ale takie jest nasze obecne podejście do najlepszego rozwiązania tego problemu. Czy istnieje alternatywne podejście, które powinniśmy rozważyć?

Zauważyliśmy, że gdy funkcja skalarna jest używana w rekurencyjnym CTE, powoduje to, że zapytanie zapisuje się w dzienniku kontroli dla każdego wiersza w zestawie wyników.

Niektóre funkcje o wartościach skalarnych są dostarczane przez dostawcę, których nie możemy usunąć ani przenieść do alternatywnej bazy danych.


6
We've found that some queries will write to the audit log the use of a scalar function for every row in a result set.- To jeden z najwspanialszych efektów ubocznych skalarnych UDF, jakie kiedykolwiek słyszałem i dużo słyszałem.
— Erik Darling

3
Czy istnieje opcja tworzenia UDF, których nie chcesz kontrolować w osobnej bazie danych (która nie jest kontrolowana) i wywoływania ich za pomocą 3-częściowej nazwy?
— Scott Hodgin

@ ScottHodgin, podoba mi się to obejście, ale w naszych okolicznościach istnieją pewne Wartościowe Funkcje Skalarne, które są dostarczane przez dostawcę, których nie możemy usunąć ani przenieść do alternatywnej bazy danych.
— Mark Iannucci

Osoby podążające za tym mogą zastanawiać się, co powoduje, że zapytanie zapisuje w dzienniku kontroli dla każdego wiersza w zestawie wyników; zauważyliśmy, że ma to miejsce, gdy funkcja skalarna jest używana w rekurencyjnym CTE.
— Mark Iannucci

Odpowiedzi:


6

Jest kilka opcji, które udało mi się uruchomić. Wszystkie opcje dotyczą odmian predykatów filtrów. UWAGA: należy wyłączyć Audyt serwera, aby wprowadzić zmiany, a następnie włączyć go ponownie .

Po pierwsze, najbardziej ogólnym podejściem jest odfiltrowanie wszystkich skalarnych UDF. Możesz to zrobić za pomocą class_typepola audytu. Dokumentacja wskazuje, że to pole jest VARCHAR(2), ale nie pozwala na określenie ciągu. Dostałem jednak następujące rzeczy do pracy:

ALTER SERVER AUDIT [servAudit]
WHERE ([class_type] <> 20038); -- EXECUTE Scalar UDF

(więcej informacji na temat tego dochodzenia tutaj: Tajemnica audytu serwera: Filtrowanie typu_klasa powoduje błąd Msg 25713 )

Następne najbardziej ogólne podejście nie wchodzi w grę, ponieważ stwierdzono, że jest to baza danych dostarczona przez dostawcę i dlatego nie można wprowadzać żadnych zmian. Opiszę to ostatnie.

Najmniej ogólne podejście (ale takie, które zdecydowanie działa) to odfiltrowanie konkretnej nazwy funkcji:

ALTER SERVER AUDIT [servAudit]
WHERE ([object_name]<>'function_name');

Lub, jeśli wiele nazw:

ALTER SERVER AUDIT [servAudit]
WHERE ([object_name]<>'function_name1' AND [object_name]<>'function_name2');

Chociaż nie jest to bardzo ogólne, podejście to powinno być dobre, ponieważ liczba funkcji do odfiltrowania powinna być dość mała i nie będzie zbyt często, gdy wprowadzane są nowe funkcje.

Wreszcie, dla innych osób, które zmagają się z tą sytuacją i nie są ograniczone do dokonywania zmian: możesz umieścić funkcje we własnym schemacie, a następnie odfiltrować tylko ten schemat. Jest to bardziej ogólne niż oddzielne filtrowanie funkcji. Zakładając, że utworzysz Schemat o nazwie fni umieścisz w nim funkcje:

ALTER SERVER AUDIT [servAudit]
WHERE ([schema_name]<>'fn');

RÓWNIEŻ, w odniesieniu do następujących dwóch komentarzy w pytaniu:

Niestety, SQL Server nie zezwala na relacyjny operator IN (prawdopodobnie dlatego, że nie chce zapytać za każdym razem, gdy musi zapisywać w dzienniku kontroli).

i:

Chcielibyśmy uniknąć zapisywania przechowywanego proc, który na stałe koduje object_id w klauzuli WHERE

INOperator nie jest problemem. To prawda, że ​​nie jest obsługiwane, ale jest tylko skrótem do listy ORwarunków. Rzeczywistym problemem jest użycie T-SQL. Dozwolone są tylko literały - ciągi lub liczby - Więc i tak nie byłbyś w stanie wykonać Procedury składowanej. Nie można także korzystać z wbudowanych funkcji.


dziękuję za tę odpowiedź. Jesteśmy w trakcie wdrażania tej zmiany i zaakceptuję tę odpowiedź, gdy potwierdzimy, że działa ona w naszym środowisku.
— Mark Iannucci

1
@MarkIannucci Thanks! Ponadto poprawiłem drobny błąd w mojej idealnej sugestii. Skopiowałem i wkleiłem z testów, w których filtrowałem funkcje FOR zamiast funkcji WSZYSTKO, ALE. Zmieniłem, =aby być <>w mojej odpowiedzi. Właśnie go przetestowałem i działa zgodnie z reklamą :-)
— Solomon Rutzky
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.