Design do banco de dados: nova tabela versus novas colunas

38

(Isso foi sugerido para ser republicado aqui no StackOverflow)

Atualmente, possui uma tabela .. e precisa começar a adicionar novas colunas de dados a ela. Nem todo registro (mesmo avançando com novos dados após adicionar as novas colunas de dados) terá dados. Então, eu estou querendo saber se isso é mais adequado para uma nova tabela, pois é realmente uma extensão de algumas das linhas de dados e não é aplicável a todas as linhas.

Em outras palavras, como haverá muitas colunas não utilizadas para esses novos elementos de dados, parece que isso seria mais adequado para uma nova tabela?

A primeira tabela é um registro de visualizações de página (atualmente 2 milhões de registros)

- identidade
- Endereço de IP
- vezes visualizadas
- created_at timestamp
- encontro

para cada endereço IP, é feito um registro por dia - e visualizações de página consecutivas são adicionadas às visualizações de vezes por dia

campos adicionais seriam para rastreamento de ponto de origem (por exemplo, origem / mídia / campanha do Google Analytics)

Nem toda visita terá essa informação. Suponho que cerca de 10% das linhas terão os dados (como geralmente são atribuídos apenas na primeira visita)

O principal uso dos dados seria atribuir a origem das pessoas. Isso pode acabar sendo usado com mais frequência (o que parece se prestar à mesa única)

Aprecie o feedback - pode adicionar mais se necessário

cgmckeever
fonte

Respostas:

29

Você está lutando com o particionamento vertical. Esta é uma técnica de design de banco de dados físico para melhorar o desempenho. Como em qualquer técnica de design de banco de dados físico, sua aplicabilidade depende das consultas específicas que você está tentando otimizar e se essa técnica as otimizará. Do ponto de vista lógico, se esses novos campos dependem da chave candidata para sua entidade, são fatos sobre ela que pertencem a ela. Primeiro, certifique-se de entender completamente a dependência funcional desses novos campos nas suas chaves candidatas para verificar se realmente são fatos sobre as visualizações de página diárias. Se estiverem, decidir particioná-las em outra tabela é uma otimização de desempenho que só deve ser feita se atingir seus objetivos de desempenho.

Em geral, o particionamento vertical é útil se você consultar essas novas colunas com pouca frequência e distinta das outras colunas na tabela original. Ao colocar essas colunas em outra tabela que compartilha a mesma PK da tabela existente, você pode consultá-la diretamente quando desejar essas novas colunas e obter muito mais rendimento, pois você terá muito mais linhas por página em disco para esta nova tabela como todas as colunas da tabela original não estarão nessas linhas. No entanto, se você sempre consultar essas colunas junto com as colunas da tabela original, uma partição vertical não faria muito sentido, pois você sempre precisará da junção externa para obtê-las. As páginas das tabelas no disco entram no buffer pool de um DBMS de forma independente, nunca pré-ingressadas, e, portanto, essa associação terá que ocorrer com cada execução de consulta, mesmo que os dados sejam fixados no buffer pool. Nesse cenário, torná-las NULLABLE colunas na tabela original permitiria ao mecanismo de armazenamento DBMS armazená-las eficientemente quando NULL e eliminaria a necessidade de ingressar na recuperação.

Parece-me que o seu caso de uso é o último e adicioná-los como NULLABLE à sua tabela original é o caminho a seguir. Mas, como acontece com todo o resto no design do banco de dados, isso depende e, para tomar a decisão certa, você precisa conhecer a carga de trabalho esperada e do que depende uma boa escolha. Um bom exemplo de um caso de uso adequado para o particionamento vertical seria um painel de pesquisa de pessoas, em que seu aplicativo tem informações muito raramente preenchidas sobre uma pessoa em que alguém pode querer pesquisar, mas raramente o faz. Se você colocar essas informações em uma tabela diferente, terá algumas boas opções de desempenho. Você pode escrever a pesquisa para ter 2 consultas - uma que use as informações principais, sempre preenchidas, para pesquisar apenas (como sobrenome ou ssn), e aquele que une as informações muito raramente preenchidas com frequência apenas quando solicitadas para pesquisa. Ou você pode tirar proveito do otimizador DBMS se for inteligente o suficiente para reconhecer, para um determinado conjunto de variáveis ​​do host, que a junção externa não é necessária e não a executará, e, portanto, você só precisa criar 1 consulta.

Qual plataforma DBMS você está usando? A maneira pela qual a plataforma lida com o armazenamento de coluna NULL otimiza sua consulta, bem como a disponibilidade de suporte a colunas esparsas (o SQL Server possui isso) afetará a decisão. Por fim, eu recomendaria experimentar os dois projetos em um ambiente de teste com dados e carga de trabalho com tamanho de produção e ver quais alcançam melhor seus objetivos de desempenho.

Todd Everett
fonte
Não está claro para mim o que você quer dizer com "No entanto, se você sempre consultar essas colunas junto com as colunas da tabela original, uma partição vertical não faria muito sentido, pois você sempre terá que fazer uma junção externa para obtê-las". , você só precisaria fazer uma junção externa quando desejar que as colunas primárias estejam ou não disponíveis, caso contrário, você utilizaria uma INNER JOIN, e isso será benéfico na maioria dos casos (reduzindo o número de linhas analisadas )
Jmoreno 25/05
Obrigado por toda a ajuda aqui .. De fato, eu adicionei os campos, mas depois de pensar nisso, vi que deveria ter algumas outras tabelas para identificar melhor tudo. O que finalmente veio foi o visitante visitor_visits (que tem um visitor_id e contém a fonte) page_views (que possui vistor_id e visitor_visit_id), pois quero saber exatamente qual page_view é atribuída à visita, adicionei esse link. Eu lutei com ele um pouco, mas eu acho que foi a decisão certa
cgmckeever
10

Pessoalmente, inclino-me a adicionar colunas à tabela existente. A nova tabela realmente não compra nada para você:

  • você realmente não economiza muito espaço, porque os valores NULL na tabela original não ocupam espaço, e a nova tabela precisa de algum tipo de identificador que, de qualquer maneira, compensa a economia
  • suas consultas se tornam mais complexas ... where newcolumn is not nullse torna umleft outer join

Na tabela única, isso significa apenas que o tamanho da linha pode variar de página para página - mas isso não deve afetar muitas das páginas existentes, especialmente se o índice em cluster estiver em uma coluna monotonicamente crescente (identidade ou data / hora).

Aaron Bertrand
fonte
Como a tabela atualmente não é ampla (com base na sua descrição) e esses dados não serão muito amplos, eu concordo.
HLGEM
4

Dadas as informações que você forneceu e com apenas a normalização geral sendo o objetivo, eu provavelmente adicionaria colunas anuláveis, mas você não forneceu informações suficientes sobre como os dados serão usados ​​para saber qual a melhor maneira de modelar os dados é.

Dependendo de como você realmente está usando esses dados, convém considerar um modelo de dados diferente. Se você estiver colocando esses dados para geração de relatórios, poderá procurar um modelo dimensional, que pode ser mais eficiente para certos tipos de geração de relatórios - por exemplo, a análise da hora do dia funciona bem com uma dimensão de data e hora dividida.

Para responder a perguntas analíticas, como "qual é a hora do dia mais popular para visitas de campanhas como X" ou "que dia de uma campanha vemos mais visitas por hora", uma única coluna de tempo de dados não funciona muito bem (mas isso pode até ser dividido em um modelo relacional), e há muitos casos em que você pode tratar o endereço IP como uma dimensão (talvez com algum tipo de dados geográficos em um floco de neve).

Cade Roux
fonte