guides/directory-data-model.html

O MODELO DE DADOS

Como projeto o schema para um site de diretório em escala de seis dígitos. Entidades, atributos, slugs, índices, e as decisões de design que se compõem.

O MODELO DE DADOS

← Blog All posts in this topic

As decisões de schema que se compõem

Um site de diretório em 28K linhas (HostList.io) ou 137K linhas (Not Another Sunday) funciona ou falha em decisões de schema tomadas na primeira semana. As decisões que mais importam: como entidades são normalizadas, como atributos são armazenados, como slugs são gerados, o que é indexado.

Cada uma delas é reversível em pequena escala e proibitivamente cara de corrigir em escala de seis dígitos. Acerte cedo.

Entidades, atributos, junções

Uma tabela de entidades com uma linha mestre por empresa, lugar ou produto. Chave primária UUID estável, uma coluna por atributo intrínseco (name, founded_year, primary_market). Evite colocar atributos em colunas JSON nesta camada; eles devem ser consultáveis como colunas de primeira classe.

Uma tabela de atributos por eixo ortogonal. categories (cada linha é uma categoria), regions (cada linha é uma região), price_tiers (cada linha é um tier). Estas são as dimensões entre as quais as entidades são agrupadas.

Relacionamentos muitos-para-muitos via tabelas de junção: entity_categories, entity_regions, entity_features. Nunca armazene listas de categorias separadas por vírgula na tabela entities; as tabelas de junção são o que tornam a filtragem, listagem e contagem rápidas.

Slugs são para sempre

Depois que uma página de diretório é indexada pelo Google, o slug não deve mudar. Use geração de slug determinística a partir do nome da entidade com tratamento de colisão via sufixo numérico: nginx-hosting, nginx-hosting-2 se uma colisão ocorrer.

Mantenha uma tabela slug_history separada mapeando qualquer slug histórico para o slug canônico atual. Quando um nome de entidade precisa mudar (correção, rebranding), o novo slug canônico é gerado, o slug antigo entra na tabela de histórico e um redirecionamento 301 permanente é configurado automaticamente.

O custo de acertar errado a estabilidade de slug em um site com 28K linhas é catastrófico: cada cadeia de redirecionamento que você cria é uma pequena erosão de ranking, e não há boas correções após o fato.

Indexabilidade no nível de linha

Adicione uma coluna booleana indexable à tabela entities, padrão true, com lógica que a inverte para false quando a entidade não atende aos limites de qualidade (conteúdo único insuficiente, atributos obrigatórios ausentes, sem links internos de entrada).

A consulta do sitemap filtra em indexable = true. O renderizador de página adiciona meta noindex quando indexable = false. Ambos são derivados da mesma coluna, então permanecem em sincronização atomicamente.

Em HostList.io, aproximadamente 18K de 28K entidades são indexáveis em qualquer momento. Os outros 10K são rastreáveis mas não indexáveis, o que mantém a superfície indexada limpa e as páginas indexadas restantes mais fortes.

Índices que importam

Índice na slug para a busca de page-render. Índice em (indexable, last_updated_at) para a query do sitemap. Índice em (category_id, indexable) na tabela de junção para páginas de listagem de categorias. Índice em (region_id, indexable) para páginas regionais.

Em escala de centenas de milhares de linhas, uma query de page-render sem índice leva segundos. Com índices apropriados, leva milissegundos. O impacto no tempo de build se compõe: 28K renderizações de página a 100ms cada é 47 minutos; a 10ms cada é 5 minutos.

Execute EXPLAIN ANALYZE em toda query de page-render em escala. O planejador de query padrão erra em joins com formato de diretório mais frequentemente do que você esperaria.

WHEN YOU ARE READY TO TALK