¿Cómo filtrar el uso de la función definida por el usuario de valor escalar de los datos de auditoría de SQL Server?

12

Tenemos una base de datos SQL Server que tiene una especificación de auditoría de base de datos que audita todas las acciones de ejecución en la base de datos.

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

Hemos encontrado que algunas consultas escribirán en el registro de auditoría el uso de una función escalar para cada fila en un conjunto de resultados. Cuando esto sucede, el registro se llena antes de que podamos colocarlo en su lugar de descanso final y tenemos un espacio en nuestro registro.

Desafortunadamente, debido a razones de cumplimiento, no podemos simplemente dejar de auditar cada EXECUTEdeclaración.

Nuestro primer pensamiento para el enfoque de este problema es usar una WHEREcláusula en la Auditoría del servidor para filtrar la actividad. El código se veía así:

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

Desafortunadamente, SQL Server no permite el operador IN relacional (probablemente porque no quiere consultar cada vez que tiene que escribir en el registro de auditoría).

Nos gustaría evitar escribir un proceso almacenado que codifique object_iden la WHEREcláusula, pero ese es nuestro pensamiento actual sobre la mejor manera de abordar este problema. ¿Existe un enfoque alternativo que deberíamos considerar?

Hemos observado que cuando la función escalar está en uso en un CTE recursivo, hace que la consulta escriba en el registro de auditoría para cada fila del conjunto de resultados.

Hay algunas funciones de valor escalar entregadas por un proveedor que no podemos eliminar o mover a una base de datos alternativa.

Mark Iannucci
fuente
66
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.- Ese es uno de los efectos secundarios más magníficos de los UDF escalares que he escuchado, y he escuchado mucho.
Erik Darling
3
¿Existe la opción de crear UDF que no desea auditar en una base de datos separada (que no se audita) e invocarlos a través de un nombre de 3 partes?
Scott Hodgin el
@ScottHodgin, me gusta la solución, pero en nuestras circunstancias hay algunas funciones de valor escalar que son entregadas por un proveedor que no podemos eliminar o mover a una base de datos alternativa.
Mark Iannucci el
Los que siguen pueden preguntarse qué caso hace que la consulta escriba en el registro de auditoría para cada fila de un conjunto de resultados; Hemos notado que ocurre cuando la función escalar está en uso en un CTE recursivo.
Mark Iannucci el

Respuestas:

6

Hay algunas opciones que pude poner a trabajar. Todas las opciones tratan con variaciones de predicados de filtro. NOTA: debe deshabilitar la Auditoría del servidor para realizar cambios y luego volver a habilitarla .

Primero, el enfoque más genérico es filtrar todos los UDF escalares. Puede hacerlo utilizando el class_typecampo de auditoría. La documentación indica que este campo es VARCHAR(2), pero no permite especificar una cadena. Sin embargo, conseguí que funcionara lo siguiente:

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

(Más información sobre esa investigación aquí: misterio de auditoría del servidor: el filtrado de class_type obtiene el mensaje de error 25713 )

El siguiente enfoque más genérico no es una opción, ya que se dijo que esta es una base de datos suministrada por el proveedor y, por lo tanto, no se pueden realizar cambios. Así que cubriré eso último.

El enfoque menos genérico (pero definitivamente funciona) es filtrar el nombre de la función específica:

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

O, si hay varios nombres:

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

Si bien no es muy genérico, este enfoque debería estar bien, ya que el número de funciones para filtrar debería ser bastante pequeño, y no será muy frecuente que se introduzcan nuevas funciones.

Finalmente, para otros que enfrentan esta situación y no tienen restricciones para realizar cambios: puede colocar funciones en su propio esquema y luego filtrar solo ese esquema. Esto es más genérico que filtrar las funciones individualmente. Suponiendo que cree un Esquema llamado fny coloque las funciones en él:

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

TAMBIÉN, con respecto a los siguientes dos comentarios en la pregunta:

Desafortunadamente, SQL Server no permite el operador IN relacional (probablemente porque no quiere consultar cada vez que tiene que escribir en el registro de auditoría).

y:

Nos gustaría evitar escribir un proceso almacenado que codifique el object_id en la cláusula WHERE

El INoperador no es el problema. Es cierto que no es compatible, pero es solo una forma abreviada de una lista de ORcondiciones. El problema real es el uso de T-SQL. Solo se permiten literales (cadenas o números). Por lo tanto, no habría podido ejecutar un Procedimiento almacenado de todos modos. Tampoco puedes usar las funciones integradas.

Solomon Rutzky
fuente
gracias por esta respuesta. Estamos en el proceso de implementar este cambio, y aceptaré esta respuesta cuando confirmemos que funciona en nuestro entorno.
Mark Iannucci el
1
@ MarkIannucci Gracias! Además, acabo de corregir un error menor en mi sugerencia ideal. Había copiado y pegado de las pruebas en las que estaba filtrando las funciones FOR en lugar de CUALQUIER COSA PERO funciones. Cambié el =para estar <>en mi respuesta. También lo probé y funciona como se anuncia :-)
Solomon Rutzky