Estoy atrapado en un debate en el trabajo, y necesito algunos consejos sobre posibles trampas que podría pasar por alto.
Imagine un escenario en el que se utiliza un disparador para copiar registros eliminados a una tabla de auditoría. El activador usa SELECT *. Todos señalan y gritan y nos dicen lo malo que es esto.
Sin embargo, si se realiza una modificación en la Estructura de la Tabla principal, y se pasa por alto la Tabla de auditoría, entonces el Disparador generará un error para que las personas sepan que la tabla de Auditoría también necesita modificación.
El error se detectará durante las pruebas en nuestros servidores DEV. Pero debemos asegurarnos de que los Matches de producción sean DEV, por lo que permitimos SELECCIONAR * en los Sistemas de producción (solo disparadores).
Entonces, mi pregunta es: me están presionando para eliminar SELECT *, pero no estoy seguro de qué otra manera asegurarme de que estamos capturando automáticamente errores de desarrollo de esta naturaleza, ¿alguna idea o es esta mejor práctica?
He reunido un ejemplo a continuación:
--Create Test Table
CREATE TABLE dbo.Test(ID INT IDENTITY(1,1), Person VARCHAR(255))
--Create Test Audit Table
CREATE TABLE dbo.TestAudit(AuditID INT IDENTITY(1,1),ID INT, Person VARCHAR(255))
--Create Trigger on Test
CREATE TRIGGER [dbo].[trTestDelete] ON [dbo].[Test] AFTER DELETE
NOT FOR REPLICATION
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TestAudit([ID], [Person])
SELECT *
FROM deleted
END
--Insert Test Data into Test
INSERT INTO dbo.Test VALUES
('Scooby')
,('Fred')
,('Shaggy')
--Perform a delete
DELETE dbo.Test WHERE Person = 'Scooby'
ACTUALIZACIÓN (reformulación de la pregunta):
Soy un DBA y necesito asegurarme de que los Desarrolladores no proporcionen scripts de implementación mal pensados al contribuir a nuestra Documentación de mejores prácticas. SELECT * provoca un error en DEV cuando el desarrollador pasa por alto la tabla de auditoría (esta es una red de seguridad), por lo que el error se detecta al principio del proceso de desarrollo. Pero en algún lugar de la Constitución de SQL: la segunda enmienda dice "No usarás SELECT *". Así que ahora hay un impulso para deshacerse de la red de seguridad.
¿Cómo reemplazaría la red de seguridad, o debería considerar que esta es la mejor práctica para los activadores?
ACTUALIZACIÓN 2: (solución)
Gracias por todos sus comentarios, no estoy seguro si tengo una respuesta clara porque parece ser un tema muy gris. Pero colectivamente, ha proporcionado puntos de discusión que pueden ayudar a nuestros desarrolladores a avanzar en la definición de sus mejores prácticas.
Gracias Daevin
por su contribución, su respuesta proporciona la base para algunos mecanismos de prueba que nuestros Desarrolladores pueden implementar. +1
Gracias CM_Dayton
, sus sugerencias que contribuyen a las mejores prácticas pueden ser beneficiosas para cualquier persona que esté desarrollando Desencadenadores de auditoría. +1
Muchas gracias a ypercube
, has pensado mucho sobre los problemas relacionados con las tablas que experimentan diferentes formas de cambios de definición. +1
En conclusión:
Is Select * ok in a tigger?
Sí, es un área gris, no siga ciegamente la ideología "Seleccionar * es malo".
Am I asking for Trouble?
Sí, hacemos más que solo agregar nuevas columnas a las tablas.
fuente
SELECT *
ser perezoso, pero como tienes una razón legítima para usarlo, es más gris que blanco y negro. Lo que debe intentar hacer es algo como esto , pero ajústelo para que no solo tenga el mismo recuento de columnas, sino que los nombres de columna y los tipos de datos sean los mismos (ya que alguien podría cambiar los tipos de datos y aún causar problemas en la base de datos que normalmente no se detectan) con suSELECT *
'red de seguridad'.SELECT *
como red de seguridad, pero no atrapará todos los casos. Por ejemplo, si suelta una columna y la agrega nuevamente. Esto cambiará el orden de las columnas y (a menos que todas las columnas sean del mismo tipo) las inserciones en la tabla de auditoría fallarán o provocarán la pérdida de datos debido a las conversiones de tipo implícitas.Respuestas:
Típicamente, se considera programación "perezosa".
Dado que está insertando específicamente dos valores en su
TestAudit
tabla aquí, tendré cuidado de asegurarme de que su selección también obtenga exactamente dos valores. Porque si, por alguna razón, esaTest
tabla tiene o alguna vez obtiene una tercera columna, este disparador fallará.No está directamente relacionado con su pregunta, pero si está configurando una tabla de auditoría, también agregaría algunas columnas adicionales a su
TestAudit
tabla para ...Entonces eso resulta en una consulta como:
De esa forma, obtiene las columnas exactas que necesita y audita de qué / cuándo / por qué / de quién trata el evento de auditoría.
fuente
Comenté esto en su pregunta, pero pensé que intentaría presentar una solución de código.
Por lo general, estoy de acuerdo con
SELECT *
ser flojo, pero como tienes una razón legítima para usarlo, es más gris que blanco y negro.Lo que debería (en mi opinión) intentar hacer es algo como esto , pero ajústelo para asegurarse de que los nombres de columna y los tipos de datos sean los mismos (ya que alguien podría cambiar los tipos de datos y aún causar problemas en la base de datos que normalmente no se detectan con su
SELECT *
seguridad red'.Incluso podría crear una función que le permita verificar rápidamente si la versión de auditoría de la tabla coincide con la versión que no es de auditoría:
El
SELECT ... EXCEPT SELECT ...Audit
le mostrará qué columnas en la tabla no están en la tabla de Auditoría. Incluso podría cambiar la función para devolver el nombre de columnas que no son iguales en lugar de solo si se asignan o no, o incluso generar una excepción.A continuación, puede ejecutar este antes de pasar de
DEV
aPRODUCTION
los servidores para cada tabla en el PP, usando un cursor sobre:fuente
La declaración que indicará el activador fallará y el activador fallará. Sería una mejor práctica documentar el desencadenante y el seguimiento de auditoría para que sepa modificar la consulta para agregar las columnas en lugar de especificar el *.
Como mínimo, debe modificar el desencadenador para que pueda fallar con gracia al registrar errores en una tabla y quizás poner una alerta en la tabla en la que el desencadenador registra los errores.
Esto también recuerda, puede poner un activador o alerta cuando alguien altera la tabla y agrega más columnas o elimina columnas, para notificarle que agregue el activador.
En cuanto al rendimiento, creo que * no cambia nada, solo aumenta las posibilidades de fallas en el futuro cuando las cosas cambian y también puede causar latencia de red cuando extrae más información a través de la red cuando lo necesita. Hay un momento y un lugar para *, pero creo que, como se describió anteriormente, tiene mejores soluciones y herramientas para probar.
fuente
Si las estructuras de su tabla de auditoría o original cambian, está garantizando que tendrá un problema con su select *.
Si cualquiera de los dos cambia, el disparador producirá un error.
Podrías hacerlo:
Pero como dice CM_Dayton, esa es una programación perezosa y abre la puerta a otras inconsistencias. Para que este escenario funcione, debe asegurarse absolutamente de que está actualizando la estructura de ambas tablas al mismo tiempo.
fuente