Sim, estou ciente de que a normalização dos dados deve ser minha prioridade (como está).
- Tenho uma tabela com 65 colunas armazenando dados de veículos com colunas:
used_vehicle
,color
,doors
,mileage
,price
e assim por diante, totalizando 65. - Agora, posso dividir isso e ter uma
Vehicle
tabela,VehicleInterior
,VehicleExterior
,VehicleTechnical
,VehicleExtra
(todos um-para-um com aVehicle
tabela principal).
Vamos supor que terei cerca de 5 milhões de linhas (veículos).
On SELECT
com uma WHERE
cláusula: O desempenho será melhor pesquisando (ambos os casos indexados pelo menos em IDs
):
Vehicle
tabela com 65 colunas ouVehicle
tabela comJOINS
outras quatro tabelas (todas com 5 milhões de linhas) para retornar todos os dados relacionados aVehicle
?
(De acordo com o mecanismo de banco de dados, considere PostgreSQL e/ou MySQL).
Aprecia verdadeiramente quaisquer insights detalhados que você possa ter de sua experiência anterior?
As atualizações serão raras, se houver, e as seleções serão principalmente para todas as colunas (página de detalhes do veículo) e informações principais (algumas colunas) para a lista de resultados de pesquisa e, de fato, talvez a melhor solução seja duas tabelas: uma com informações principais (algumas colunas) e a outra tabela com o restante das colunas.
Assumindo que estamos falando de relacionamentos 1:1 entre todas as tabelas.
O armazenamento geral é praticamente sempre (substancialmente) mais barato com uma única tabela em vez de várias tabelas na relação 1:1. Cada linha tem 28 bytes de sobrecarga, além de mais alguns bytes para preenchimento extra. E você precisa armazenar a coluna PK com cada tabela. E tenha um índice separado (redundante) em cada uma dessas colunas... O tamanho importa para o desempenho.
Isso é verdade mesmo se muitas colunas forem NULL na maioria das linhas porque o armazenamento NULL é muito barato :
Ao recuperar todas as colunas, uma única tabela é substancialmente mais rápida do que 5 tabelas unidas. Também é muito mais simples . Cinco tabelas podem ser difíceis de juntar se nem todas as linhas estiverem presentes em todas as tabelas. Com
WHERE
condições direcionadas a uma única tabela, é fácil anexar outras tabelas comLEFT JOIN
. Não é tão trivial se você tiver predicados em várias tabelas ...O particionamento vertical ainda pode melhorar o desempenho de determinadas consultas. Por exemplo, se 90% de suas consultas recuperam as mesmas 5 colunas das 65 disponíveis, isso seria mais rápido com uma tabela contendo apenas essas 5 colunas.
OTOH, você pode atender a essas consultas em algumas colunas selecionadas com um índice de "cobertura" que permite varreduras somente de índice .
Outro candidato para particionamento vertical: se você tiver muitas atualizações em apenas algumas colunas, enquanto o restante quase nunca muda. Pode ser consideravelmente mais barato dividir linhas nesse caso, já que o Postgres escreve uma nova versão de linha para cada atualização. Há exceções para grandes valores armazenados fora de linha ("TOASTed"). Mais detalhes:
Realmente depende da situação completa. Em caso de dúvida, opte pela solução simples de ter uma única mesa, principalmente se ela retratar bem a realidade: No seu exemplo, todos esses são atributos de um carro e fazem sentido juntos.
Uma seleção em uma única mesa pode ser mais rápida. (Mas não sempre). Se você tivesse todos os dados em uma única tabela plana, depois de encontrar seu veículo, você já teria todos os detalhes. No entanto, isso pode envolver mais E/S e potencialmente mais atraso.
Você também perde a eficiência da normalização. Por exemplo, se 1 carro tiver muitos modelos com diferentes opções. Com dados normalizados, você poderia retornar todo o conjunto de registros com menos E/S do que se estivesse em uma tabela de fatos. Mesmo que o mecanismo de banco de dados precise fazer mais computação, ainda pode ser mais rápido.
Este é um db de referência de todos os carros? Ou uma lista de veículos em segunda mão? Haveria muitos exemplos da mesma marca/modelo com as mesmas opções?
Devo qualificar minha resposta como sendo rdbms genéricos em vez de específicos do Postgres. Eu defiro a resposta detalhada de Erwin específica para Postgres.