Estrategias de escalamiento de bases de datos: réplicas de lectura, fragmentación y más
El rendimiento de la base de datos es el cuello de botella en el 78 % de los problemas de escalado de aplicaciones web. Las aplicaciones pueden escalar horizontalmente con un esfuerzo mínimo, pero las bases de datos se resisten al escalamiento horizontal. Las estrategias que elija para el escalado de la base de datos determinan si su aplicación atiende a 100 usuarios o a 100 000 usuarios con un rendimiento aceptable.
Esta guía cubre el espectro completo de estrategias de escalado de bases de datos, desde optimizaciones simples que retrasan la necesidad de escalar hasta técnicas avanzadas como la fragmentación horizontal.
Conclusiones clave
- Optimice las consultas y agregue índices antes de agregar infraestructura: esto resuelve el 60% de los problemas de rendimiento de la base de datos
- Las réplicas de lectura son la estrategia de escalamiento de menor riesgo y manejan el 80 % de las cargas de trabajo con mucha lectura.
- La agrupación de conexiones es obligatoria una vez que su aplicación ejecuta más de 10 instancias
- La fragmentación horizontal es un último recurso que introduce una complejidad significativa en la aplicación.
La escalera de ascenso
Escale en este orden. Cada paso es más barato y menos riesgoso que el siguiente:
Paso 1: Optimización de consultas (gratis)
Antes de agregar infraestructura, asegúrese de que su base de datos existente esté funcionando de manera óptima.
-- Find slow queries in PostgreSQL
SELECT
calls,
mean_exec_time::numeric(10,2) AS avg_ms,
total_exec_time::numeric(10,2) AS total_ms,
query
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;
Optimizaciones comunes:
- Agregar índices faltantes para columnas filtradas con frecuencia
- Reemplace
SELECT *con listas de columnas específicas - Utilice
EXPLAIN ANALYZEpara identificar escaneos secuenciales en tablas grandes - Agregar índices compuestos para cláusulas WHERE de varias columnas
- Implementar paginación con paginación de conjunto de claves en lugar de
OFFSET
-- Bad: OFFSET pagination (scans all skipped rows)
SELECT * FROM orders ORDER BY created_at DESC LIMIT 20 OFFSET 10000;
-- Good: Keyset pagination (index-only scan)
SELECT * FROM orders
WHERE created_at < '2026-03-15T10:00:00Z'
ORDER BY created_at DESC
LIMIT 20;
Paso 2: Escala vertical ($)
Aumente la CPU, la RAM y el almacenamiento en su servidor de base de datos existente. Esto gana tiempo y no requiere cambios en la aplicación.
| Tamaño de instancia | CPU virtual | RAM | Conexiones | Costo Mensual (RDS) |
|---|---|---|---|---|
| db.t3.medio | 2 | 4 GB | 100 | $65 |
| db.r6g.grande | 2 | 16 GB | 200 | $175 |
| db.r6g.xlarge | 4 | 32 GB | 400 | $350 |
| db.r6g.2xlarge | 8 | 64 GB | 800 | $700 |
La mayoría de las aplicaciones alcanzan su límite con 64 GB de RAM y 8 vCPU. Más allá de eso, el escalamiento vertical tiene un costo prohibitivo.
Paso 3: Agrupación de conexiones ($)
Application (50 pods x 20 connections = 1,000 connections)
|
v
PgBouncer (25 database connections, transaction pooling)
|
v
PostgreSQL (25 active connections, manageable)
Configuración de PgBouncer:
[databases]
app = host=db.example.com port=5432 dbname=production
[pgbouncer]
listen_port = 6432
listen_addr = 0.0.0.0
auth_type = md5
pool_mode = transaction
default_pool_size = 25
max_client_conn = 1000
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3
Paso 4: Leer réplicas ($$)
Las réplicas de lectura manejan consultas SELECT, descargando entre el 60% y el 90% de la carga de la base de datos de la principal.
Arquitectura:
Write queries --> Primary database
|
Replication (async)
|
+----+----+
| |
Read queries --> Replica 1 Replica 2
Enrutamiento a nivel de aplicación (ejemplo de Drizzle ORM):
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
const primaryPool = new Pool({ connectionString: process.env.DATABASE_URL });
const replicaPool = new Pool({ connectionString: process.env.DATABASE_REPLICA_URL });
export const primaryDb = drizzle(primaryPool);
export const replicaDb = drizzle(replicaPool);
// In service code:
// Write operations use primaryDb
async createOrder(data: OrderInput) {
return primaryDb.insert(orders).values(data).returning();
}
// Read operations use replicaDb
async getOrders(organizationId: string) {
return replicaDb.select().from(orders)
.where(eq(orders.organizationId, organizationId))
.orderBy(desc(orders.createdAt));
}
Consideraciones sobre el retraso de la replicación: la replicación asíncrona introduce un retraso (normalmente de 10 a 100 ms). Inmediatamente después de una escritura, la lectura de la réplica puede devolver datos obsoletos. Utilice el primario para lecturas que siguen a escrituras en el mismo flujo de usuario.
Paso 5: Almacenamiento en caché ($$)
El almacenamiento en caché de Redis elimina por completo las consultas repetidas a la base de datos.
async getProduct(id: string): Promise<Product> {
const cacheKey = `product:${id}`;
// Check cache first
const cached = await this.redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Cache miss: query database
const product = await this.db.select().from(products)
.where(eq(products.id, id))
.limit(1);
// Cache for 5 minutes
await this.redis.setex(cacheKey, 300, JSON.stringify(product[0]));
return product[0];
}
Estrategia de invalidación de caché: Invalidar al escribir. Cuando se actualiza un producto, elimine la clave de caché. Utilice un patrón de caché aparte (la aplicación administra el caché) en lugar de escritura simultánea (la base de datos administra el caché).
Paso 6: fragmentación horizontal ($$$)
La fragmentación distribuye datos entre múltiples instancias de bases de datos según una clave de fragmentación.
| Estrategia de fragmentación | Descripción | Mejor para |
|---|---|---|
| Basado en hash | Hash la clave del fragmento, distribuir uniformemente | Distribución uniforme de datos |
| Basado en rango | Asignar rangos a fragmentos (por ejemplo, A-M, N-Z) | Series temporales, datos geográficos |
| Basado en inquilinos | Un fragmento por inquilino/organización | SaaS multiinquilino |
Cuándo fragmentar:
- La base de datos única supera 1 TB y sigue creciendo
- El rendimiento de escritura supera lo que puede manejar un único primario
- Los costos de escalamiento vertical superan los $2000/mes sin margen de maniobra
Cuándo NO fragmentar:
- No has agotado los pasos 1-5
- Tus datos caben en una única base de datos de 500 GB
- Las consultas entre fragmentos son comunes en su aplicación.
Optimizaciones específicas de PostgreSQL
Partición (antes de fragmentar)
La partición de tablas de PostgreSQL divide tablas grandes en tablas físicas más pequeñas mientras mantiene una única tabla lógica:
-- Partition orders by month
CREATE TABLE orders (
id UUID PRIMARY KEY,
organization_id UUID NOT NULL,
created_at TIMESTAMP NOT NULL,
total DECIMAL(10,2)
) PARTITION BY RANGE (created_at);
CREATE TABLE orders_2026_01 PARTITION OF orders
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE orders_2026_02 PARTITION OF orders
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
CREATE TABLE orders_2026_03 PARTITION OF orders
FOR VALUES FROM ('2026-03-01') TO ('2026-04-01');
La partición mejora el rendimiento de las consultas de rango de tiempo entre 10 y 100 veces en tablas grandes porque PostgreSQL solo escanea las particiones relevantes.
Aspiración y mantenimiento
-- Check table bloat
SELECT
schemaname,
relname,
n_live_tup,
n_dead_tup,
round(n_dead_tup::numeric / greatest(n_live_tup, 1) * 100, 2) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;
Configure autovacuum agresivamente para tablas de alta escritura:
ALTER TABLE orders SET (
autovacuum_vacuum_threshold = 100,
autovacuum_vacuum_scale_factor = 0.05,
autovacuum_analyze_threshold = 50,
autovacuum_analyze_scale_factor = 0.02
);
Supervisión del rendimiento de la base de datos
Realice un seguimiento de estas métricas para comprender cuándo y cómo escalar:
| Métrica | Herramienta | Umbral de alerta |
|---|---|---|
| Latencia de consulta (P95) | pg_stat_statements | >500ms |
| Conexiones activas | pg_stat_actividad | >80% del máximo |
| Proporción de aciertos de caché | pg_stat_database | <95% |
| Retraso de replicación | pg_stat_replication | >1 segundo |
| Hinchazón de mesa | pg_stat_user_tables | >20% tuplas muertas |
| Espera de E/S de disco | iostato / CloudWatch | >20ms |
Una tasa de aciertos de caché inferior al 95% es el indicador más claro de que necesita más memoria. Aumentar shared_buffers y effective_cache_size suele ser más económico y rápido que agregar réplicas de lectura.
Seguimiento del rendimiento de consultas
-- Enable pg_stat_statements (postgresql.conf)
-- shared_preload_libraries = 'pg_stat_statements'
-- Find the top 10 most time-consuming queries
SELECT
queryid,
calls,
mean_exec_time::numeric(10,2) AS avg_ms,
total_exec_time::numeric(10,2) AS total_ms,
rows,
query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
Revise las 10 consultas principales semanalmente. Optimizar incluso una única consulta ejecutada con frecuencia puede reducir la carga general de la base de datos entre un 10 y un 30 %.
Preguntas frecuentes
¿Cómo sabemos cuándo es el momento de escalar?
Supervise tres métricas: latencia de consulta P95 (alerta a 500 ms), utilización de la conexión (alerta al 80%) y utilización de la CPU (alerta al 70% sostenida). Si alcanza estos umbrales con regularidad, pase al siguiente paso en la escalera de ascenso. No optimice previamente --- escale cuando los datos se lo indiquen.
Leer réplicas o almacenamiento en caché: ¿cuál primero?
Comience con el almacenamiento en caché. El almacenamiento en caché de Redis es más sencillo de implementar, elimina más carga (los accesos al caché omiten la base de datos por completo) y cuesta menos. Agregue réplicas de lectura cuando su tasa de aciertos de caché ya sea superior al 80 % pero la base de datos principal todavía esté bajo presión por errores de caché y operaciones de escritura.
¿Cómo funciona el escalado de bases de datos con Odoo?
Odoo utiliza PostgreSQL exclusivamente. Comience con la optimización de consultas (Odoo genera consultas complejas para generar informes). Agregue PgBouncer para agrupar conexiones cuando supere los 50 usuarios simultáneos. Utilice réplicas de lectura para consultas de informes (configure la opción --db-replica de Odoo). ECOSIRE proporciona optimización del rendimiento de Odoo incluido el ajuste de la base de datos.
¿Vale la pena pagar una prima por la base de datos administrada (RDS/Cloud SQL)?
Sí, para la mayoría de las empresas. Las bases de datos administradas manejan copias de seguridad, parches, conmutación por error y monitoreo automatizados. La prima de costo del 30 al 40 % sobre PostgreSQL autoadministrado se compensa con el tiempo de ingeniería que ahorra. La excepción son las implementaciones a gran escala donde la prima de costo de una instancia grande excede el costo de un DBA a tiempo parcial.
¿Qué viene después?
El escalamiento de la base de datos es un componente de una estrategia más amplia de escalamiento de infraestructura. Combínelo con optimización de CDN para activos estáticos, escalado automático de Kubernetes para pods de aplicaciones y pruebas de carga para validar sus decisiones de escalado en condiciones realistas.
Comuníquese con ECOSIRE para obtener consultoría sobre optimización de bases de datos, o consulte nuestra guía DevOps para obtener la hoja de ruta completa de la infraestructura.
Publicado por ECOSIRE: ayuda a las empresas a escalar la infraestructura de datos con confianza.
Escrito por
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
Haga crecer su negocio con ECOSIRE
Soluciones empresariales en ERP, comercio electrónico, inteligencia artificial, análisis y automatización.
Artículos relacionados
Migraciones de bases de datos sin tiempo de inactividad con Drizzle ORM
Ejecute migraciones de bases de datos sin tiempo de inactividad utilizando Drizzle ORM. Cubre el patrón de contrato de expansión, cambios de esquema compatibles con versiones anteriores, estrategias de reversión e integración CI/CD para PostgreSQL.
Rocíe ORM con PostgreSQL: Guía completa
Guía completa de Drizzle ORM con PostgreSQL: diseño de esquemas, migraciones, consultas con seguridad de tipos, relaciones, transacciones y patrones de producción para aplicaciones TypeScript.
ERP para SaaS y empresas tecnológicas: operaciones a escala
Guía completa de ERP para SaaS y empresas de tecnología: gestión de ingresos por suscripciones, crecimiento de personal, adquisiciones de proveedores e informes financieros a escala.