Eu tenho tentado criar um banco de dados para ir com um conceito de projeto e me deparei com o que parece ser um problema muito debatido. Eu li alguns artigos e algumas respostas do Stack Overflow que afirmam que nunca (ou quase nunca) é bom armazenar uma lista de IDs ou algo semelhante em um campo - todos os dados devem ser relacionais etc.
O problema que estou enfrentando, no entanto, é que estou tentando criar um atribuidor de tarefas. As pessoas criarão tarefas, as atribuirão a várias pessoas e elas serão salvas no banco de dados.
É claro que, se eu salvar essas tarefas individualmente em "Pessoa", terei que ter dezenas de colunas fictícias "TaskID" e gerenciá-las micro porque podem haver de 0 a 100 tarefas atribuídas a uma pessoa, por exemplo.
Por outro lado, se eu salvar as tarefas em uma tabela "Tarefas", precisarei ter dezenas de colunas fictícias "PersonID" e gerenciá-las de forma micro - o mesmo problema de antes.
Para um problema como esse, não há problema em salvar uma lista de IDs de uma forma ou de outra ou simplesmente não estou pensando em outra maneira de conseguir isso sem violar princípios?
fonte
VARCHAR ARRAY
) para armazenar uma lista de tags. Provavelmente não é assim que elas acabam sendo armazenadas posteriormente, mas as listas podem ser extremamente úteis durante os estágios de prototipagem, quando você não tem mais nada para apontar e não deseja criar todo o esquema do banco de dados antes de poder faça qualquer outra coisa.Respostas:
A palavra-chave e o conceito-chave que você precisa investigar é a normalização do banco de dados .
O que você faria, em vez de adicionar informações sobre as atribuições à pessoa ou às tabelas de tarefas, é adicionar uma nova tabela com essas informações de atribuição, com relacionamentos relevantes.
Exemplo, você tem as seguintes tabelas:
Pessoas:
Tarefas:
Você criaria uma terceira tabela com atribuições. Esta tabela modelaria o relacionamento entre as pessoas e as tarefas:
Teríamos, então, uma restrição de chave estrangeira, de modo que o banco de dados imponha que o PersonId e o TaskIds tenham que ser IDs válidos para esses itens estrangeiros. Para a primeira linha, podemos ver
PersonId is 1
, portanto , Alfred , está atribuído aTaskId 3
, Vacas leiteiras .O que você deve ser capaz de ver aqui é que você pode ter poucas ou tantas atribuições por tarefa ou por pessoa quanto desejar. Neste exemplo, Ezekiel não recebeu nenhuma tarefa e Alfred recebeu 2. Se você tiver uma tarefa com 100 pessoas, a tarefa
SELECT PersonId from Assignments WHERE TaskId=<whatever>;
produzirá 100 linhas, com uma variedade de Pessoas diferentes atribuídas. Você pode encontrarWHERE
no PersonId todas as tarefas atribuídas a essa pessoa.Se você quiser retornar consultas substituindo os IDs pelos Nomes e pelas tarefas, aprenderá como JOIN tables.
fonte
Você está fazendo duas perguntas aqui.
Primeiro, você pergunta se não há problema em armazenar listas serializadas em uma coluna. Sim, tudo bem. Se o seu projeto exige isso. Um exemplo pode ser ingredientes do produto para uma página de catálogo, onde você não deseja tentar rastrear cada ingrediente individualmente.
Infelizmente, sua segunda pergunta descreve um cenário em que você deve optar por uma abordagem mais relacional. Você precisará de 3 mesas. Um para as pessoas, um para as tarefas e um que mantém a lista de qual tarefa está atribuída a quais pessoas. Essa última seria vertical, uma linha por combinação de pessoa / tarefa, com colunas para sua chave primária, ID da tarefa e ID da pessoa.
fonte
O que você está descrevendo é conhecido como um relacionamento "muitos para muitos", no seu caso entre
Person
eTask
. Geralmente, é implementado usando uma terceira tabela, às vezes chamada de tabela "link" ou "referência cruzada". Por exemplo:fonte
task_id
primeiro, se estiver fazendo consultas filtradas por tarefa.O único momento em que você pode armazenar mais de um item de dados em um único campo é quando esse campo é usado apenas como uma única entidade e nunca é considerado como sendo composto por esses elementos menores. Um exemplo pode ser uma imagem, armazenada em um campo BLOB. Ele é composto por muitos e muitos elementos menores (bytes), mas estes não significam nada para o banco de dados e só podem ser usados todos juntos (e parecem muito para um Usuário Final).
Como uma "lista" é, por definição, composta de elementos menores (itens), esse não é o caso aqui e você deve normalizar os dados.
Não. Você terá algumas linhas em uma Tabela de interseção (também conhecida como entidade fraca) entre Pessoa e Tarefa. Os bancos de dados são realmente bons em trabalhar com muitas linhas; eles são realmente um lixo ao trabalhar com muitas colunas [repetidas].
Belo exemplo claro dado por whatsisname.
fonte
Pode ser legítimo em certos campos pré-calculados.
Se algumas de suas consultas forem caras e você decidir optar por campos pré-calculados atualizados automaticamente usando acionadores de banco de dados, pode ser legítimo manter as listas em uma coluna.
Por exemplo, na interface do usuário você deseja mostrar esta lista usando a exibição em grade, em que cada linha pode abrir detalhes completos (com listas completas) após clicar duas vezes:
Você mantém a segunda coluna atualizada por acionador quando o cliente visita um novo artigo ou por tarefa agendada.
Você pode disponibilizar esse campo mesmo para pesquisa (como texto normal).
Para tais casos, manter listas é legítimo. Você só precisa considerar o caso de possivelmente exceder o tamanho máximo do campo.
Além disso, se você estiver usando o Microsoft Access, os campos com vários valores oferecidos são outro caso de uso especial. Eles lidam com suas listas em um campo automaticamente.
Mas você sempre pode voltar ao formulário normalizado padrão mostrado em outras respostas.
Resumo: Formas normais de banco de dados são modelo teórico necessário para entender aspectos importantes da modelagem de dados. Mas é claro que a normalização não leva em consideração o desempenho ou outro custo da recuperação dos dados. Está fora do escopo desse modelo teórico. Mas o armazenamento de listas ou outras duplicatas pré-calculadas (e controladas) geralmente é exigido pela implementação prática.
À luz do exposto acima, na implementação prática, preferiríamos que a consulta dependesse da forma normal perfeita e executasse 20 segundos ou consulta equivalente, dependendo de valores pré-calculados que levam 0,08 s? Ninguém gosta que seu produto de software seja acusado de lentidão.
fonte
Dadas duas tabelas; nós os chamaremos de Person e Task, cada um com seu próprio ID (PersonID, TaskID) ... a idéia básica é criar uma terceira tabela para uni-los. Vamos chamar essa tabela de PersonToTask. No mínimo, ele deve ter seu próprio ID, assim como os outros dois. Portanto, quando se trata de designar alguém para uma tarefa; não será mais necessário atualizar a tabela Person, basta inserir uma nova linha na PersonToTaskTable. E a manutenção se torna mais fácil - a necessidade de excluir uma tarefa se torna DELETE com base no TaskID, não é mais necessário atualizar a tabela Person e a análise associada
Que tal um relatório simples ou quem está atribuído a uma tarefa?
É claro que você poderia fazer muito mais; um TimeReport pode ser feito se você adicionar os campos DateTime para TaskAssigned e TaskCompleted. Está tudo nas tuas mãos
fonte
Pode funcionar se você tiver chaves primárias legíveis por humanos e desejar uma lista de tarefas sem precisar lidar com a natureza vertical de uma estrutura de tabela. ou seja, é muito mais fácil ler a primeira tabela.
A questão seria: a lista de tarefas deve ser armazenada ou gerada sob demanda, o que dependeria em grande parte de requisitos como: com que frequência a lista é necessária, com que precisão existem quantas linhas de dados, como os dados serão usados etc. .. após o qual a análise das trocas para a experiência do usuário e o cumprimento dos requisitos devem ser feitos.
Por exemplo, comparando o tempo que levaria para recuperar as 2 linhas versus executar uma consulta que geraria as 2 linhas. Se demorar e o usuário não precisar da lista mais atualizada (* esperando menos de 1 alteração por dia), ela poderá ser armazenada.
Ou, se o usuário precisar de um registro histórico de tarefas atribuídas a ele, também faria sentido se a lista fosse armazenada. Portanto, isso realmente depende do que você está fazendo, nunca diga nunca.
fonte
Você está pegando o que deveria ser outra mesa, girando 90 graus e colocando-o em outra mesa.
É como ter uma tabela de pedidos onde você possui itemProdcode1, itemQuantity1, itemPrice1 ... itemProdcode37, itemQuantity37, itemPrice37. Além de ser complicado de lidar programaticamente, você pode garantir que amanhã alguém deseje pedir 38 coisas.
Eu faria do seu jeito apenas se a 'lista' não for realmente uma lista, ou seja, onde ela se encontra como um todo e cada item de linha individual não se refere a alguma entidade clara e independente. Nesse caso, basta colocar tudo em algum tipo de dado que seja grande o suficiente.
Portanto, um pedido é uma lista, uma lista de materiais é uma lista (ou uma lista de listas, o que seria ainda mais um pesadelo para implementar "de lado"). Mas uma nota / comentário e um poema não são.
fonte
Se "não estiver ok", é bastante ruim que todo site Wordpress tenha uma lista em wp_usermeta com wp_capabilities em uma linha, lista de demitidos_wp_pointers em uma linha e outros ...
De fato, em casos como esse, pode ser melhor para a velocidade, pois você quase sempre deseja a lista . Mas o Wordpress não é conhecido por ser o exemplo perfeito de melhores práticas.
fonte