Eu tenho uma mesa representando filmes. Os campos são:
id (PK), title, genre, runtime, released_in, tags, origin, downloads
.
Meu banco de dados não pode ser poluído por linhas duplicadas, portanto, desejo impor exclusividade. O problema é que filmes diferentes podem ter o mesmo título ou até os mesmos campos, exceto tags
e downloads
. Como impor exclusividade?
Pensei em duas maneiras:
- faça todos os campos, exceto
downloads
a chave primária. Eu estou me mantendo dedownloads
fora, pois é JSON e provavelmente afetará o desempenho. - mantenha apenas
id
como chave primária, mas adicione uma restrição exclusiva a todas as outras colunas (exceto, novamentedownloads
).
Li essa pergunta que é muito parecida, mas não entendi bem o que devo fazer. Atualmente, esta tabela não está relacionada a nenhuma outra tabela, mas no futuro poderia ser.
No momento, tenho pouco menos de 20.000 registros, mas espero que o número cresça. Não sei se isso é um pouco relevante para o problema.
Edição: Eu modifiquei o esquema e aqui está como eu criaria a tabela:
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)
);
Também adicionei a timestamp
coluna, mas isso não é um problema, pois não vou tocá-la. Por isso, será sempre automático e único.
Respostas:
Sua definição de tabela parece razoável agora. Com todas as colunas,
NOT NULL
aUNIQUE
restrição funcionará conforme o esperado - exceto erros de digitação e pequenas diferenças ortográficas, o que pode ser bastante comum, receio. Considere o comentário de @ a_horse .Alternativa com índice exclusivo funcional
A outra opção seria um índice exclusivo funcional (semelhante ao que o @Dave comentou ). Mas eu usaria um
uuid
tipo de dados para otimizar o tamanho e o desempenho do índice.A conversão da matriz para o texto não é
IMMUTABLE
(devido à sua implementação genérica):Portanto, você precisa de uma pequena função auxiliar para declará- la imutável:
Use-o para a definição de índice:
SQL Fiddle.
Mais detalhes:
Você pode usar o UUID gerado como PK, mas eu ainda usaria a
serial
coluna com seus 4 bytes, o que é simples e barato para referências FK e outros fins. Um UUID seria uma ótima opção para sistemas distribuídos que precisam gerar valores de PK independentemente. Ou para mesas muito grandes, mas não há filmes suficientes em nosso sistema solar para isso.Prós e contras
Uma restrição exclusiva é implementada com um índice exclusivo nas colunas envolvidas. Coloque as colunas relevantes na definição de restrição primeiro e você terá um índice útil para outros fins como benefício colateral.
Existem outros benefícios específicos, aqui está uma lista:
O índice exclusivo funcional é (potencialmente muito) menor em tamanho, o que pode torná-lo substancialmente mais rápido. Se suas colunas não forem muito grandes, a diferença não será grande. Há também o pequeno custo indireto para o cálculo.
Concatenar todas as colunas pode introduzir falsos positivos (
'foo ' || 'bar' = 'foob ' || 'ar'
, mas isso parece muito improvável para este caso. Os erros de digitação são muito mais prováveis que você pode ignorá-la com segurança aqui.Exclusividade e matrizes
As matrizes teriam que ser classificadas de forma consistente para fazer sentido em qualquer arranjo exclusivo que dependa do
=
operador'{1,2}' <> '{2,1}'
. Sugiro tabelas de pesquisa paragenre
,tag
eorigin
comserial
PK e entradas exclusivas, que permitem a pesquisa difusa de elementos de matriz. Então:implemente relacionamentos n: m totalmente normalizados que também fornecem integridade referencial. A exclusividade de cada conjunto de referências é mais difícil de estabelecer; você pode usar um
MATERIALIZE VIEW
(MV) com matrizes agregadas como trampolim.ou operar com matrizes classificadas de referências FK (que ainda não podem ser suportadas com restrições FK). As ferramentas do módulo adicional de matriz podem ser úteis:
De qualquer forma, trabalhando com matrizes diretamente ou com um esquema normalizado e uma visualização materializada, a pesquisa pode ser muito eficiente com o índice e os operadores certos:
Se você estiver usando o Postgres 9.4 ou posterior, considere em
jsonb
vez dejson
.fonte
Imagine que você está com um grupo de amigos e a conversa se transforma em filmes. Alguém pergunta: "O que você achou dos 'Os Três Mosqueteiros'?" Você responde: "Qual?"
Quais informações adicionais você precisaria para ter certeza absoluta de que ambos estão pensando no mesmo filme? O nome do diretor? O estúdio de produção? O ano em que foi lançado? Um dos nomes da estrela? Alguma combinação de dois ou mais?
A resposta para a minha pergunta e a sua são as mesmas.
No entanto, eu não acho que esse gênero seja um bom candidato. Uma razão, o gênero é um critério subjetivo demais. A ação dos três mosqueteiros? drama? aventura? comédia? ação e aventura? comédia romântica? Costumo ver o mesmo filme listado em diferentes gêneros. Mesmo quando você permite vários gêneros, o usuário pode selecionar um totalmente diferente, não listado no filme que está procurando.
Até os tempos de execução podem diferir, especialmente entre as versões de teatro e VCR / DVD / b-ray.
Portanto, você precisa de atributos objetivos e rígidos que não mudam de um release para outro. Infelizmente, isso pode excluir o nome do filme, já que se sabe que os filmes foram renomeados, especialmente após o lançamento de uma sequência.
E a data de lançamento? O lançamento teatral de 1993? O lançamento do videocassete de 1999? O lançamento em DVD de 2004? Você entendeu a ideia.
Venha para pensar sobre o assunto, e todos os filmes dirigidos por Alan Smithee? O real diretor finalmente se adiantou para colocar seu nome no projeto após o fato? Eu não sei.
É melhor parar enquanto ainda existem alguns critérios.
Alguns pontos adicionais:
fonte
A coluna ID não tem nenhuma vantagem quando se trata da exclusividade que você deseja / precisa aplicar. A exclusividade de qualquer combinação de atributos nunca será imposta pela adição de um ID sem sentido. Sua "vantagem" mostra apenas quando você chega ao ponto em que precisa de uma nova tabela que precise de uma chave estrangeira para esta. Nesse caso, e se você incluiu o ID, poderá usá-lo como o FK em sua nova tabela. (Mas não pense que será um almoço grátis. A desvantagem dessa abordagem é que você provavelmente se encontrará escrevendo mais junções com o simples objetivo de buscar informações que poderiam perfeitamente fazer parte da nova tabela que você criou. )
fonte