J'ai une table représentant des films. Les champs sont les suivants :
id (PK), title, genre, runtime, released_in, tags, origin, downloads
.
Ma base de données ne peut pas être polluée par des lignes dupliquées, je souhaite donc appliquer l'unicité. Le problème est que différents films peuvent avoir le même titre, voire les mêmes champs sauf tags
et downloads
. Comment imposer l'unicité?
J'ai pensé à deux façons:
- faire tous les champs sauf
downloads
la clé primaire. Je me retiensdownloads
car c'est JSON et cela aura probablement un impact sur les performances. - conserver uniquement
id
comme clé primaire, mais ajouter une contrainte unique à toutes les autres colonnes (sauf, encore une foisdownloads
).
J'ai lu cette question qui est très similaire, mais je ne comprenais pas très bien quoi faire. Actuellement, ce tableau n'est lié à aucun autre tableau, mais pourrait l'être à l'avenir.
Pour le moment, j'ai un peu moins de 20 000 disques, mais je m'attends à ce que ce nombre augmente. Je ne sais pas si cela est quelque peu pertinent pour la question.
EDIT: J'ai modifié le schéma et voici comment je créerais la table:
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)
);
J'ai également ajouté la timestamp
colonne, mais ce n'est pas un problème car je n'y toucherai pas. Ce sera donc toujours automatique et unique.
Réponses:
La définition de votre table semble désormais raisonnable. Avec toutes les colonnes,
NOT NULL
laUNIQUE
contrainte fonctionnera comme prévu - à l'exception des fautes de frappe et des différences orthographiques mineures, qui peuvent être assez courantes, je le crains. Considérez le commentaire de @ a_horse .Alternative avec index unique fonctionnel
L'autre option serait un index fonctionnel unique (similaire à ce que @Dave a commenté ). Mais j'utiliserais un
uuid
type de données pour optimiser la taille et les performances de l'index.La conversion du tableau en texte n'est pas
IMMUTABLE
(en raison de son implémentation générique):Par conséquent, vous avez besoin d'une petite fonction d'aide pour la déclarer immuable:
Utilisez-le pour la définition de l'index:
SQL Fiddle.
Plus de détails:
Vous pouvez utiliser l'UUID généré comme PK, mais j'utiliserais toujours la
serial
colonne avec ses 4 octets, ce qui est simple et bon marché pour les références FK et à d'autres fins. Un UUID serait une excellente option pour les systèmes distribués qui doivent générer des valeurs PK indépendamment. Ou pour de très grandes tables, mais il n'y a presque pas assez de films dans notre système solaire pour cela.Avantages et inconvénients
Une contrainte unique est implémentée avec un index unique sur les colonnes impliquées. Mettez d'abord les colonnes pertinentes dans la définition de contrainte et vous disposez d'un indice utile à d'autres fins comme garantie.
Il existe d'autres avantages spécifiques, voici une liste:
L' indice fonctionnel unique est (potentiellement beaucoup) plus petit, ce qui peut le rendre beaucoup plus rapide. Si vos colonnes ne sont pas trop grandes, la différence ne sera pas grande. Il y a aussi les petits frais généraux pour le calcul.
La concaténation de toutes les colonnes peut introduire des faux positifs (
'foo ' || 'bar' = 'foob ' || 'ar'
, mais cela semble très peu probable dans ce cas. Les fautes de frappe sont tellement plus susceptibles que vous puissiez les ignorer en toute sécurité ici.Unicité et tableaux
Les tableaux devraient être triés de manière cohérente pour avoir du sens dans tout arrangement unique reposant sur l'
=
opérateur, car'{1,2}' <> '{2,1}'
. Je suggère des tables de recherche pourgenre
,tag
etorigin
avecserial
PK et des entrées uniques, qui permettent une recherche floue des éléments du tableau. Alors:soit implémenter des relations n: m entièrement normalisées qui fournissent également une intégrité référentielle. L'unicité de chaque ensemble de références est plus difficile à établir, vous pouvez utiliser un
MATERIALIZE VIEW
(MV) avec des tableaux agrégés comme tremplin.ou fonctionner avec des tableaux triés de références FK (qui ne peuvent pas encore être pris en charge avec des contraintes FK). Les outils du module supplémentaire intarray peuvent être utiles:
Quoi qu'il en soit, en travaillant directement avec des tableaux ou avec un schéma normalisé et une vue matérialisée, la recherche peut être très efficace avec le bon index et les bons opérateurs:
Si vous utilisez Postgres 9.4 ou une version ultérieure, pensez à la
jsonb
place dejson
.la source
Imaginez que vous sortiez avec un groupe d'amis et que la conversation tourne au cinéma. Quelqu'un demande: "Qu'avez-vous pensé des" Trois mousquetaires "?" Vous répondez: "Lequel?"
De quelles informations supplémentaires auriez-vous besoin pour être absolument certain que vous pensez tous les deux au même film? Le nom du réalisateur? Le studio de production? L'année de sa sortie? Un des noms de la star? Une combinaison de deux ou plus?
La réponse à ma question et la vôtre sont les mêmes.
Cependant, je ne pense pas que ce genre serait un bon candidat. L'une des raisons pour lesquelles le genre est un critère beaucoup trop subjectif. L'action des «trois mousquetaires»? drame? aventure? comédie? action-aventure? comédie romantique? Je vois souvent le même film répertorié sous différents genres. Même lorsque vous autorisez plusieurs genres, votre utilisateur peut en sélectionner un entièrement différent, non répertorié avec le film réel qu'il recherche.
Même les temps d'exécution peuvent différer, en particulier entre les versions cinéma et magnétoscope / DVD / rayons B.
Vous avez donc besoin d'attributs durs et objectifs qui ne changeront pas d'un communiqué de presse à un autre. Malheureusement, cela peut exclure le nom du film car les films ont été renommés, surtout après la sortie d'une suite.
Et la date de sortie? La sortie en salles de 1993? La sortie du magnétoscope de 1999? La sortie DVD de 2004? Vous avez eu l'idée.
À bien y penser, qu'en est-il de tous ces films réalisés par Alan Smithee? Le vrai réalisateur a-t-il finalement décidé de mettre son nom sur le projet après coup? Je ne sais pas.
Hmm, je ferais mieux de m'arrêter tant qu'il reste des critères.
Quelques points supplémentaires:
la source
La colonne ID n'a aucun avantage en ce qui concerne l'unicité que vous souhaitez / devez appliquer. L'unicité de toute combinaison d'attributs ne sera jamais appliquée en ajoutant un ID sans signification. Son «avantage» ne s'affiche que lorsque vous arrivez au point où vous auriez besoin d'une nouvelle table qui a besoin d'une clé étrangère pour celle-ci. Dans ce cas, et SI vous avez inclus l'ID, vous pouvez l'utiliser comme FK dans votre nouvelle table. (Mais ne pensez pas que ce sera un déjeuner gratuit. L'inconvénient d'une telle approche est que vous vous retrouverez probablement à écrire plus de jointures dans le seul but de récupérer des informations qui auraient parfaitement pu faire partie de ce nouveau tableau que vous avez créé. )
la source