Tengo una mesa que representa películas. Los campos son:
id (PK), title, genre, runtime, released_in, tags, origin, downloads
.
Mi base de datos no puede contaminarse con filas duplicadas, por lo que quiero imponer unicidad. El problema es que diferentes películas podrían tener el mismo título, o incluso los mismos campos, excepto tags
y downloads
. ¿Cómo hacer cumplir la singularidad?
Pensé en dos formas:
- hacer todos los campos excepto
downloads
la clave primaria. Me mantengodownloads
alejado ya que es JSON y probablemente afectará el rendimiento. - mantenga solo
id
como clave principal, pero agregue una restricción única con todas las otras columnas (excepto, nuevamente,downloads
).
Leí esta pregunta que es muy similar, pero no entendí bien qué debería hacer. Actualmente esta tabla no está relacionada con ninguna otra tabla, pero en el futuro podría estarlo.
Por el momento tengo un poco menos de 20,000 registros, pero espero que el número crezca. No sé si esto es algo relevante para el problema.
EDITAR: modifiqué el esquema y así es como crearía la tabla:
CREATE TABLE movies (
id serial PRIMARY KEY,
title text NOT NULL,
runtime smallint NOT NULL CHECK (runtime >= 0),
released_in smallint NOT NULL CHECK (released_in > 0),
genres text[] NOT NULL default ARRAY[]::text[],
tags text[] NOT NULL default ARRAY[]::text[],
origin text[] NOT NULL default ARRAY[]::text[],
downloads json NOT NULL,
inserted_at timestamp NOT NULL default current_timestamp,
CONSTRAINT must_be_unique UNIQUE(title,runtime,released_in,genres,tags,origin)
);
También agregué la timestamp
columna, pero eso no es un problema ya que no lo tocaré. Por lo tanto, siempre será automático y único.
Respuestas:
La definición de su tabla parece razonable en todo momento. Con todas las columnas,
NOT NULL
laUNIQUE
restricción funcionará como se esperaba, excepto los errores tipográficos y las pequeñas diferencias en la ortografía, lo que puede ser bastante común, me temo. Considere el comentario de @ a_horse .Alternativa con índice único funcional
La otra opción sería un índice único funcional (similar a lo que comentó @Dave ). Pero usaría un
uuid
tipo de datos para optimizar el tamaño y el rendimiento del índice.La conversión de la matriz al texto no es
IMMUTABLE
(debido a su implementación genérica):Por lo tanto, necesita una pequeña función auxiliar para declararla inmutable:
Úselo para la definición del índice:
SQL Fiddle.
Más detalles:
Puede usar el UUID generado como PK, pero igual usaría la
serial
columna con sus 4 bytes, lo cual es simple y económico para referencias FK y otros fines. Un UUID sería una gran opción para sistemas distribuidos que necesitan generar valores PK independientemente. O para mesas muy grandes, pero no hay suficientes películas en nuestro sistema solar para eso.Pros y contras
Se implementa una restricción única con un índice único en las columnas involucradas. Coloque primero las columnas relevantes en la definición de restricción y tendrá un índice útil para otros fines como beneficio colateral.
Hay otros beneficios específicos, aquí hay una lista:
El índice único funcional es (potencialmente mucho) más pequeño en tamaño, lo que puede hacerlo considerablemente más rápido. Si sus columnas no son demasiado grandes, la diferencia no será demasiado. También existe el pequeño costo indirecto para el cálculo.
La concatenación de todas las columnas puede introducir falsos positivos (
'foo ' || 'bar' = 'foob ' || 'ar'
pero eso parece muy poco probable para este caso. Los errores tipográficos son mucho más probables que puede ignorarlos aquí de forma segura.Unicidad y arrays
Las matrices tendrían que clasificarse consistentemente para tener sentido en cualquier arreglo único que dependa del
=
operador porque'{1,2}' <> '{2,1}'
. Sugiero tablas de búsqueda paragenre
,tag
yorigin
conserial
PK y entradas únicas, que permiten la búsqueda difusa de elementos de matriz. Entonces:o bien implementan relaciones n: m totalmente normalizadas que también proporcionan integridad referencial. La singularidad de cada conjunto de referencias es más difícil de establecer, podría usar un
MATERIALIZE VIEW
(MV) con matrices agregadas como trampolín.u operar con matrices ordenadas de referencias FK (que aún no pueden ser compatibles con restricciones FK). Las herramientas del módulo adicional intarray pueden ser útiles:
De cualquier manera, al trabajar con matrices directamente o con un esquema normalizado y una vista materializada, la búsqueda puede ser muy eficiente con el índice y los operadores correctos:
Si está utilizando Postgres 9.4 o posterior, considere en
jsonb
lugar dejson
.fuente
Imagina que sales con un grupo de amigos y la conversación se convierte en películas. Alguien pregunta: "¿Qué pensaste de 'Los tres mosqueteros'?" Respondes, "¿Cuál?"
¿Qué información adicional necesitarías para estar absolutamente seguro de que ambos piensan en la misma película? ¿El nombre del director? El estudio de producción? ¿El año en que fue lanzado? ¿Uno de los nombres de la estrella? ¿Alguna combinación de dos o más?
La respuesta a mi pregunta y la suya son las mismas.
Sin embargo, no creo que ese género sea un buen candidato. Una razón, el género es un criterio demasiado subjetivo. ¿Es la acción de 'Los tres mosqueteros'? ¿drama? ¿aventuras? ¿comedia? ¿acción Aventura? ¿comedia romántica? A menudo veo la misma película en diferentes géneros. Incluso cuando permite múltiples géneros, su usuario puede seleccionar uno completamente diferente que no esté en la lista con la película real que está buscando.
Incluso los tiempos de ejecución pueden diferir, especialmente entre las versiones de teatro y VCR / DVD / b-ray.
Por lo tanto, necesita atributos duros y objetivos que no cambien de un comunicado de prensa a otro. Desafortunadamente, eso puede excluir el nombre de la película ya que se sabe que las películas cambian de nombre, especialmente después del lanzamiento de una secuela.
¿Qué pasa con la fecha de lanzamiento? ¿El estreno teatral de 1993? El lanzamiento de VCR de 1999? ¿El lanzamiento en DVD de 2004? Tienes la idea.
Ahora que lo pienso, ¿qué hay de todas esas películas dirigidas por Alan Smithee? ¿El director real ha dado un paso adelante para poner su nombre en el proyecto después del hecho? No lo sé.
Hmm, mejor me detengo mientras todavía quedan algunos criterios.
Algunos puntos adicionales:
fuente
La columna de ID no tiene ninguna ventaja en lo que respecta a la singularidad que desea / necesita imponer. La singularidad de cualquier combinación de atributos nunca se aplicará mediante la adición de una ID sin sentido. Su "ventaja" solo se muestra cuando llega al punto en que necesitaría una nueva tabla que necesita una clave externa para esta. En ese caso, y SI ha incluido el Id, puede usarlo como FK en su nueva tabla. (Pero no piense que será un almuerzo gratis. La desventaja de este enfoque es que probablemente se encontrará escribiendo más uniones con el solo propósito de obtener información que bien podría haber sido parte de esa nueva tabla que hizo. )
fuente