Então, estou prestes a escrever um aplicativo da Web bastante simples, atualmente estou trabalhando ativamente no esquema do banco de dados e preciso de ajuda para evitar grandes inconvenientes. Eu programo (php) há alguns anos, mas nunca tive nenhuma formação teórica, então sou totalmente ignorante sobre as melhores práticas de banco de dados e gostaria muito de aprender mais.
O problema é o seguinte: o aplicativo vai ser um CMS bem básico que permite armazenar postagens de blogs, eventos, galerias de fotos e outros itens diversos. Agora todos esses itens compartilham os mesmos atributos (mais ou menos, mas digamos que sim) que são user_id
, title
, date
, content
. Além disso, todos eles podem ser "comentados", "favoritos", "compartilhados" etc. E, finalmente, podem ser vinculados entre si (um post de blog pode se referir a um evento, que tenha fotos, etc.). Por causa disso, fico tentado a criar apenas uma tabela chamada "itens" e ter um campo "tipo" para diferenciar os itens. A consequência seria ter apenas uma tabela "join" para cada ação: "users_comments", "users_favorites", etc. e uma tabela de junção para conexões de itens entre si. Em última análise, pode haver mais tipos de itens no futuro...
Eu meio que sinto que esse é um caminho ruim e preguiçoso, principalmente por causa do desempenho, mas eu realmente gostaria de ter sua opinião sobre isso. O efeito de bloqueio tornará o site totalmente inútil, pois várias pessoas tentarão ler e escrever esses "itens"? Por que vale a pena, estou usando MySQL com MyIsam e CakePHP.
Além dessa questão está o fato de não estar acostumado com aplicações de grande escala e sempre me questionar sobre o desempenho. Acabei de ler sobre 3NF e vou continuar aprendendo essas coisas, então qualquer dica de leitura seria muito apreciada.
Olhe seriamente para a terceira forma normal. Eu usaria chaves substitutas com as chaves naturais implementadas como chaves exclusivas. Você provavelmente descobrirá que o autor pertence à sua própria tabela de autores. Você pode descobrir que tem algumas tabelas bastante semelhantes, como user_content_faves, user_author_faves, user_author_shares. Isto é normal.
Ter uma única tabela de conteúdo com uma coluna content_type pode ser apropriado. A coluna de conteúdo precisaria ser capaz de armazenar todos os tipos de conteúdo.
EDIT: Para tabelas de relacionamento, geralmente nomeio a tabela de junção concatenando os nomes das tabelas unidas, abreviando conforme necessário. Se houver vários relacionamentos entre as duas tabelas, eu uso uma das duas opções:
Presumi que você gostaria de rastrear quem favoritou ou compartilhou coisas. Verifica-se que tanto o produtor (autor ou usuário) quanto os itens de conteúdo. Portanto, você tem usuários favorecendo um produtor (user_author_faves agora user_user_faves) ou um produto (user_content_faves). Dependendo de como você compartilha,
Você pode querer considerar (e definir políticas para):
Ao indexar tabelas de relacionamento, geralmente tenho a chave primária que consiste nas chaves primárias das duas tabelas que estão sendo unidas. Um segundo índice com as chaves primárias invertidas, ou apenas a chave primária, que é a segunda coluna da chave primária, geralmente é necessário. Se o relacionamento entre duas linhas puder ocorrer mais de uma vez, a(s) coluna(s) usada(s) para diferenciar o motivo/tipo e/ou tempo (desde a data) do relacionamento precisa(m) ser adicionada(s) à chave primária.
Criar tabelas genéricas com, por exemplo, colunas discriminadoras como você parece sugerir é uma prática possível, mas um tanto tediosa ao usar um RDBMS - embora algumas estruturas ORM tenham um suporte muito bom para isso. No entanto, isso definitivamente causará um impacto no desempenho. Parece que você está procurando um modelo hierárquico em vez de um modelo relacional. Talvez um banco de dados não relacional/de documentos seja mais adequado às suas necessidades, para fornecer flexibilidade suficiente para adicionar "tipos" no futuro.
Além disso, se você insistir em usar o MySQL para esta situação, recomendo usar o InnoDB em vez do MyISAM. O MyISAM tem algumas desvantagens, como nenhum suporte de chave estrangeira real, bloqueio no nível da tabela, nenhuma recuperação de travamento, etc.