EL MODELO DE DATOS
Cómo diseño el esquema para un sitio de directorios a escala de seis cifras. Entidades, atributos, slugs, índices, y las decisiones de diseño que se componen.
Las decisiones de esquema que se componen
Un sitio de directorios con 28K filas (HostList.io) o 137K filas (Not Another Sunday) tiene éxito o fracasa según las decisiones de esquema tomadas en la primera semana. Las decisiones que más importan: cómo se normalizan las entidades, cómo se almacenan los atributos, cómo se generan los slugs, qué se indexa.
Cada una de estas es reversible a pequeña escala y prohibitivamente cara de corregir a escala de seis cifras. Acértalas desde el principio.
Entidades, atributos, uniones
Una tabla de entidades con una fila maestra por empresa, lugar o producto. Clave primaria UUID estable, una columna por atributo intrínseco (nombre, año_fundación, mercado_primario). Evita meter atributos en columnas JSON en esta capa; deben ser consultables como columnas de primera clase.
Una tabla de atributos por eje ortogonal. categories (cada fila es una categoría), regions (cada fila es una región), price_tiers (cada fila es un nivel). Estas son las dimensiones a través de las cuales se agrupan las entidades.
Relaciones muchos-a-muchos mediante tablas de unión: entity_categories, entity_regions, entity_features. Nunca almacenes listas de categorías separadas por comas en la tabla entities; las tablas de unión son lo que hace que el filtrado, listado y conteo sean rápidos.
Los slugs son para siempre
Una vez que Google indexa una página de directorio, el slug no debe cambiar. Usa generación determinista de slugs a partir del nombre de la entidad con manejo de colisiones mediante sufijo numérico: nginx-hosting, nginx-hosting-2 si ocurre una colisión.
Mantén una tabla slug_history separada que mapee cualquier slug histórico al slug canónico actual. Cuando el nombre de una entidad necesita cambiar (corrección, cambio de marca), se genera el nuevo slug canónico, el slug antiguo entra en la tabla de historial, y se configura automáticamente una redirección 301 permanente.
El costo de equivocarse con la estabilidad del slug en un sitio de 28K filas es catastrófico: cada cadena de redirección que crees es una pequeña erosión de ranking, y no hay buenas soluciones posteriores.
Indexabilidad a nivel de fila
Añade una columna booleana indexable a la tabla entities, por defecto true, con lógica que la cambia a false cuando la entidad no cumple umbrales de calidad (contenido único insuficiente, atributos requeridos faltantes, sin enlaces internos entrantes).
La consulta del sitemap filtra en indexable = true. El renderizador de páginas añade noindex meta cuando indexable = false. Ambos se derivan de la misma columna, así que se mantienen sincronizados atómicamente.
En HostList.io, aproximadamente 18K de 28K entidades son indexables en cualquier momento dado. Las otras 10K son rastreables pero no indexables, lo que mantiene la superficie indexada limpia y las páginas indexadas restantes más fuertes.
Índices que importan
Índice en slug para la búsqueda de renderizado de página. Índice en (indexable, last_updated_at) para la consulta del sitemap. Índice en (category_id, indexable) en la tabla de unión para páginas de listado de categorías. Índice en (region_id, indexable) para páginas regionales.
A escala de cientos de miles de filas, una consulta de renderizado de página sin índice toma segundos. Con índices adecuados, toma milisegundos. El impacto en el tiempo de construcción es compuesto: 28K renderizados de página a 100ms cada uno son 47 minutos; a 10ms cada uno son 5 minutos.
Ejecuta EXPLAIN ANALYZE en cada consulta de renderizado de página a escala. El planificador de consultas predeterminado se equivoca en uniones de forma de directorio más a menudo de lo que esperarías.