Tengo una aplicación (los datos se almacenan en PostgreSQL), donde la mayoría de los campos en las tablas no siempre son nulos, pero el esquema para estas tablas no impone esto. Por ejemplo, mira esta tabla falsa:
CREATE TABLE "tbl" (
"id" serial,
"name" varchar(40),
"num" int,
"time" timestamp
PRIMARY KEY ("id"),
UNIQUE ("id")
);
También name
, num
, time
No se indican explícitamente como NOT NULL
, en realidad son, debido a la aplicación ocurre en el lado de la aplicación.
Mi sensación es que debería cambiarse, pero el contrapunto es que el nivel de aplicación se asegura de que los valores nulos no puedan aparecer aquí y nadie más modifique manualmente la tabla.
Mi pregunta es : ¿Cuáles son los beneficios (rendimiento, almacenamiento, consistencia, algo más) e inconvenientes (suponiendo que ya verifiqué que no hay nulos presentes en este momento, y de la lógica de negocios no debería haber nulos) estableciendo un NOT NULL
restricción explícita ?
Tenemos un buen proceso de revisión de código y una documentación razonablemente buena, por lo que la posibilidad de que alguna persona nueva cometa algo que rompa esta restricción no es realmente suficiente para justificar el cambio.
Esta no es mi decisión, así que es exactamente por eso que estoy buscando otras justificaciones. En mi opinión, si algo no puede ser nulo y una base de datos le permite especificar que algo no es nulo, entonces simplemente hágalo. Especialmente si el cambio es super simple.
fuente
NOT NULL
restricciones no tienen ningún efecto directo sobre el tamaño de almacenamiento. Por supuesto, con todas las columnas definidasNOT NULL
, no puede haber un mapa de bits nulo para empezar. Por otro lado: el tamaño de almacenamiento suele ser mucho más pequeño si usa NULL en lugar de valores "vacíos" o ficticios para columnas sin valor real, porque el mapa de bits nulo es comparativamente mucho más pequeño (excepto en casos extremos poco comunes).Respuestas:
¿Qué sucede cuando llega un nuevo programador y tiene que escribir una aplicación contra esa base de datos? No saben que ese campo x tiene que ser
NOT NULL
.Otro programa podría suponer que todos los campos x son
NOT NULL
para realizar recuentos, pero algunos ahora se debenNULL
al nuevo programa, lo que lleva a errores inconsistentes y difíciles de rastrear.En mi humilde opinión, siempre es mejor hacer cumplir las reglas de integridad de datos lo más cerca posible de los datos, es decir, en la base de datos. De esa manera, las nuevas aplicaciones y / o programadores no pueden arruinar sus datos.
Programadores, aplicaciones, lenguajes y frameworks van y vienen. Los datos y las bases de datos tienden a persistir. La base de datos es su última línea de defensa contra datos inconsistentes y potencialmente erróneos.
Aproveche al máximo los mecanismos de aplicación de restricciones de integridad de su base de datos, incluso a expensas del rendimiento. ¡Un sistema lento que produce resultados correctos es infinitamente superior a uno rápido que hace las cosas mal!
fuente
IMHO it is always best to enforce data integrity rules as near to the data as possible
esto es realmente lo mismo que el presentimiento sobre el que escribí. Y esto es exactamente por qué estoy buscando justificaciones reales. Tenemos una revisión de código y una buena documentación, por lo que las preocupaciones sobre un nuevo desarrollador que no sabe algo no son suficientes para justificar el cambio.REAL PROGRAMMERS
leen toda la documentación (o incluso alguna) antes de atascarse en un proyecto en el que tienen un plazo ajustado?Como ya mencionaron otros en los comentarios, agregar
NOT NULL
a la especificación de su tabla puede mejorar en un manera significativa el rendimiento de sus consultas (además de las muy buenas razones metodológicas establecidas en otra respuesta).La razón es que el optimizador de consultas, sabiendo que una columna no puede tener un
NULL
valor, puede excluir pruebas especiales para tales valores, como en el casoNOT IN
vs.NOT EXISTS
Puede ver, por ejemplo, este blog , donde se muestra que no declarar un campoNOT NULL
(cuando la tabla contiene siempre valores no nulos) con una consulta determinada aumenta el tiempo de ejecución en un 500%. El resultado se muestra para SQL Server, pero un comportamiento similar podría estar presente en otros DBMS relacionales, como el suyo (sin mencionar el hecho de que su base de datos podría ser portada a otros sistemas). Una regla general que puede asumir es que cuando hay más información disponible para el optimizador de consultas, se pueden generar planes de acceso más eficientes.fuente
NOT NULL
por múltiples razones, no hay argumento al respecto. Pero el enlace al blog sobre SQL Server no es aplicable para Postgres y no prueba ninguna de las implicaciones de rendimiento que usted menciona. No digo que no haya ninguno, pero me encantaría ver evidencia real .not in
embargo, la semántica de las columnas anulables es diferente, por lo que debe haber alguna diferencia en el plan entre las dos.Implicaciones espaciales
Las implicaciones espaciales se habla en este post por @Erwin Brandstetter
En resumen, guardará un
totalColumns - 8
bit redondeado al byte más cercano (oMAXALIGN
), si su base de datos tieneNOT NULL
Implicaciones de rendimiento
Sin embargo, en esta publicación en SE de @Erwin Brandstetter , dice
@Renzo tiene una respuesta que habla sobre las implicaciones de rendimiento: supongo que nada de eso es aplicable a PostgreSQL . No puedo encontrar nada que corrobore nada de eso como relevante para PostgreSQL. Los ciclos que se guardan no se pueden cuantificar ni siquiera en la consulta más rudimentaria.
Además, realicé algunas pruebas para ver si los índices NULL eran cada vez más rápidos, y no pude comprobarlo. Puede encontrar este hilo increíblemente útil de Scott Marlowe en las listas de correo que habla sobre el planificador de consultas en 9.1 que puede usar el índice parcial en cláusulas WHERE diferentes. Probé esto ejecutando lo siguiente
Ahora creé los índices,
En ambos casos, el planificador pudo usar el índice cuando seleccionó
= 10
y usó una exploración secuencial al buscar NULL o 0 respectivamente. Ambos índices parciales eran del mismo tamaño. Y, los índices completos (no mostrados) eran del mismo tamaño. Siguiendo la misma metodología, cargué la tabla con una secuencia de1..1e5
, y un valor nulo / 0, y otra secuencia de1..1e5
. Ambos métodos pudieron encontrar el nulo / 0 con un índice que cubre toda la tabla.TLDR; Resumen
No puedo corroborar nada de una forma u otra en la mayoría de las preocupaciones de rendimiento que pensé que valía la pena probar para incluir las deficiencias del planificador. El beneficio de usar null para salvar ram es real. El espacio en disco ahorrado al no usar nulo es insignificante, y eso es una exageración en las tablas con una
NULLABLE
columna, o menos de 8 columnas. En esos casos no hay espacio en disco guardado.fuente