Estou tendo uma discussão interessante com outro designer de banco de dados sobre normalização. Neste exemplo, temos uma tabela GameTitles e cada registro deve conter o ano em que o jogo foi lançado. Ele diz que a 2NF exige que tudo deva ser normalizado; portanto, para estar em conformidade, o campo ano deve ser dividido em uma tabela ReleaseYears com sua própria chave primária, referenciada pela tabela GameTitles. Eu digo que deve permanecer como um campo na própria tabela GameTitles.
Meu argumento para isso é que um ano é apenas um valor numérico não primitivo que é estático por sua própria natureza (ou seja, 2011 sempre será 2011). Devido a isso, ele serve como seu próprio identificador e não precisa de nada para fazer referência a ele, pois é o que é. Isso também introduz manutenção adicional, pois agora você precisa adicionar um novo ano à tabela apenas para fazer referência a ela. Se você preencher previamente a tabela com um grande intervalo de anos, terá registros extras que potencialmente não terão referências a eles. Isso também aumenta o tamanho do banco de dados, pois agora você possui uma tabela extra, sobrecarga de registro e a chave primária adicional para o ano em si. Se você mantiver o ano como um campo na tabela GameTitles, você eliminará toda essa manutenção adicional e despesas gerais.
Pensamentos sobre isso?
edit: destinado a postar isso no StackOverflow. Alguém pode votar para excluir ou sinalizar isso para obter atenção?
fonte
Respostas:
O outro designer de banco de dados está simplesmente errado, mas seu raciocínio também está errado. Suponha que você comece com esta tabela, que possui uma única chave candidata, "game_title".
Você avalia se está na 2NF fazendo a si mesmo essas perguntas.
P: Primeiro de tudo, é 1NF?
A: Sim é.
P: Quais são os atributos principais (atributos que fazem parte de uma chave candidata)?
R: "game_title" é o único atributo principal.
P: Quais são os atributos não principais?
R: "year_first_released" é o único.
P: O "year_first_released" depende funcionalmente de todo o "game_title", ou apenas de uma parte dele?
R: A única chave candidata, "game_title", é uma única coluna; nem tem partes. Portanto, "year_first_released" depende funcionalmente de todo o "game_title".
Voilà. Você encontrou 2NF.
Você pode cortar alguns dos termos formais perguntando primeiro se está em 1NF e respondendo a esta pergunta.
P: Existem chaves candidatas compostas?
A: Não.
Voilà. Você encontrou 2NF novamente.
Por definição, para uma tabela violar 2NF, ela precisa ter pelo menos uma chave candidata que tenha mais de uma coluna.
Aqui estão suas razões para rejeitar a opinião de seu amigo.
Nenhuma dessas razões tem nada a ver com a existência de uma tabela no 2NF.
Ao projetar um banco de dados, não é errado considerar problemas de manutenção, tamanho do banco de dados, linhas não referenciadas, restrições de intervalo e assim por diante. É errado chamar essas coisas de normalização.
Ah, e essa tabela de duas colunas que forneci acima - está na 5NF.
fonte
Criar uma tabela separada para qualquer atributo não tem nada a ver com normalização. 2NF, 3NF, BCNF, 4NF, 5NF estão todos preocupados com a eliminação de dependências não-chave. Se você remover qualquer atributo único de uma nova tabela e substituí-lo por um atributo de chave estrangeira, as dependências na tabela serão logicamente iguais às de antes - portanto, a versão revisada da tabela não será mais ou menos normalizada do que ela foi antes.
fonte
Do meu ponto de vista, uma tabela de anos separada só faria sentido se o "ano de lançamento" não for um ano civil, mas, por exemplo, um ano fiscal que pode abranger vários anos civis (por exemplo, de outubro a outubro).
Essa tabela conteria a definição (data real de início e término) do ano fiscal
fonte
Em http://en.wikipedia.org/wiki/Second_normal_form :
Você não indicou se o ano faz parte da chave do candidato ou não, mas não tenho certeza se isso importa, porque em ambos os casos o 2NF ficaria satisfeito no que diz respeito ao ano.
Em um nível prático, é uma má idéia separar o ano por todos os motivos listados.
fonte
Não gosto do argumento contra a tabela separada por causa de seu tamanho ou por ter linhas não utilizadas. Mesmo se você colocar 1000 anos nessa tabela, o tamanho será insignificante.
Dito isto, não acho que a mesa seja necessária. Qual o sentido de ter uma mesa separada para o ano? Esses dados já estão na tabela principal e você não salva absolutamente nada criando uma segunda tabela.
O argumento pode ser diferente para uma tabela de calendário, em que cada linha representa um dia e pode ter outros atributos (dia da semana, deslocamento do UTC, se é feriado etc.).
Mas ano sozinho? Não, não vejo nenhum benefício ... E, como outros já apontaram, pergunte-lhes por que acham que isso é mais normalizado? Ou o que eles ganham? Se você estiver tentando escrever consultas como
Ao invés de
Então eu tentaria convencê-lo de que o último é muito melhor para desempenho (assumindo que o dt está indexado) e armazenamento. Se a simplicidade da codificação for primordial, eu diria que uma coluna computada persistente seria melhor que outra tabela.
fonte
Eu concordo totalmente com a resposta de Catcall, exceto em um ponto: "ano" pode não ser sempre um valor primitivo, mas acho que esse é mais um conceito de lógica de negócios do que um conceito de design de banco de dados.
Mantendo o mesmo design, vamos supor que os anos devam ser apenas aqueles que são permitidos para liberação. Dessa forma, você não está lidando com valores numéricos primitivos, mas com um subconjunto deles, e como esse subconjunto não possui uma implementação primitiva, você deve fazer o seu próprio (uma tabela separada?) E referenciá-lo (com um FK). Dessa forma, ainda estamos falando de anos, mas precisamos gerenciá-los de uma maneira diferente, porque eles mudaram conceitualmente seu significado. No entanto, eles ainda são "ano de lançamento", mas conceitualmente diferentes em termos do que eles significam para alguém no conhecimento do domínio.
Para este caso específico, digo novamente que a resposta de Catcall está correta, mas só queria salientar isso. (Desculpe, não tenha representante suficiente para comentar ainda.)
fonte