Normalmente diseño mis bases de datos siguiendo las siguientes reglas:
- Nadie más que db_owner y sysadmin tienen acceso a las tablas de la base de datos.
- Los roles de usuario se controlan en la capa de aplicación. Usualmente uso un rol db para otorgar acceso a las vistas, procedimientos almacenados y funciones, pero en algunos casos, agrego una segunda regla para proteger algunos procedimientos almacenados.
- Utilizo GATILLOS para validar inicialmente la información crítica.
CREATE TRIGGER <TriggerName>
ON <MyTable>
[BEFORE | AFTER] INSERT
AS
IF EXISTS (SELECT 1
FROM inserted
WHERE Field1 <> <some_initial_value>
OR Field2 <> <other_initial_value>)
BEGIN
UPDATE MyTable
SET Field1 = <some_initial_value>,
Field2 = <other_initial_value>
...
END
- DML se ejecuta utilizando procedimientos almacenados:
sp_MyTable_Insert(@Field1, @Field2, @Field3, ...);
sp_MyTable_Delete(@Key1, @Key2, ...);
sp_MyTable_Update(@Key1, @Key2, @Field3, ...);
¿Cree que, en este escenario, vale la pena usar RESTRICCIONES POR DEFECTO, o estoy agregando un trabajo adicional e innecesario al servidor de base de datos?
Actualizar
Entiendo que al usar la restricción DEFAULT estoy dando más información a otra persona que debe administrar la base de datos. Pero estoy principalmente interesado en el rendimiento.
Supongo que la base de datos verifica siempre los valores predeterminados, incluso si proporciono el valor correcto, por lo tanto, estoy haciendo el mismo trabajo dos veces.
Por ejemplo, ¿hay alguna manera de evitar la restricción DEFAULT dentro de una ejecución de disparo?
sql-server
tsql
Respuestas:
¿Por qué asumirías eso? ;-). Dado que los valores predeterminados existen para proporcionar un valor cuando la columna a la que están unidos no está presente en la
INSERT
declaración, asumiría exactamente lo contrario: que se ignoran por completo si la columna asociada está presente en laINSERT
declaración.Afortunadamente, ninguno de nosotros necesita asumir nada debido a esta declaración en la pregunta:
Las preguntas sobre el rendimiento son casi siempre comprobables. Por lo tanto, solo necesitamos una prueba para permitir que SQL Server (la verdadera autoridad aquí) responda esta pregunta.
PREPARAR
Ejecute lo siguiente una vez:
Ejecute las pruebas 1A y 1B individualmente, no juntas, ya que eso sesga el tiempo. Ejecute cada uno varias veces para tener una idea del tiempo promedio para cada uno.
Prueba 1A
Prueba 1B
Ejecute las pruebas 2A y 2B individualmente, no juntas, ya que eso sesga el tiempo. Ejecute cada uno varias veces para tener una idea del tiempo promedio para cada uno.
Prueba 2A
Prueba 2B
Debería ver que no hay una diferencia real en el tiempo entre las pruebas 1A y 1B, o entre las pruebas 2A y 2B. Entonces, no, no hay penalización de rendimiento para tener un
DEFAULT
definido pero no utilizado.Además, además de simplemente documentar el comportamiento previsto, debe tener en cuenta que es principalmente a usted a quien le importa que las declaraciones DML estén completamente contenidas en sus procedimientos almacenados. La gente de apoyo no les importa. Es posible que los futuros desarrolladores no sean conscientes de su deseo de tener todo el DML encapsulado dentro de esos procedimientos almacenados, o se preocupen incluso si lo saben. Y a quien sea que mantenga este DB después de que usted se haya ido (ya sea otro proyecto o trabajo) puede que no le importe o que no pueda evitar el uso de un ORM sin importar cuánto protesten. Por lo tanto, los valores predeterminados pueden ayudar, ya que le dan a la gente un "out" cuando hacen un
INSERT
, especialmente un ad-hocINSERT
hecho por un representante de soporte, ya que esa es una columna que no necesitan incluir (por eso siempre uso los valores predeterminados en la auditoría columnas de fecha).Y, se me ocurrió que se puede mostrar de manera bastante objetiva si
DEFAULT
se verifica o no cuando la columna asociada está presente en laINSERT
declaración: simplemente proporcione un valor no válido. La siguiente prueba hace exactamente eso:Como puede ver, cuando se proporciona una columna (y un valor, no la palabra clave
DEFAULT
), el valor predeterminado se ignora al 100%. Lo sabemos porqueINSERT
tiene éxito. Pero si se usa el valor predeterminado, hay un error, ya que finalmente se está ejecutando.Si bien es necesario evitar las Restricciones predeterminadas (al menos en este contexto) es completamente innecesario, en aras de la exhaustividad se puede observar que solo sería posible "evitar" una Restricción predeterminada dentro de un
INSTEAD OF
Disparador, pero no dentro de unAFTER
Disparador. De acuerdo con la documentación de CREATE TRIGGER :Por supuesto, usar un
INSTEAD OF
disparador requeriría:AFTER
disparador que habilite la restricciónSin embargo, no recomendaría exactamente hacer esto.
fuente
CURRENT_TIMESTAMP
columnas de fecha y hora. Por lo tanto, la prueba "fácil" de usar una expresión no válida no funcionará allí (y un valor no válido no se puede usarCREATE TABLE
desde que está validado), y no tengo tiempo para construir la prueba de rendimiento. Pero sospecho que la mayoría de los RDBMS los tratarían de la misma manera.No veo ningún daño significativo al tener restricciones predeterminadas. De hecho, veo una ventaja particular: ha definido el valor predeterminado en el mismo nivel de lógica que la definición de la tabla en sí. Si tiene un valor predeterminado que proporciona en su procedimiento almacenado, alguien tiene que ir allí para averiguar cuál es el valor predeterminado; y, eso no es algo que sería obvio para alguien nuevo en el sistema, necesariamente (si, por ejemplo, hereda un billón de dólares mañana, compra su propia isla tropical, y renuncia y se muda allí, dejando otra savia pobre para resolver las cosas fuera por su cuenta).
fuente