Ir al contenido

Cloud SQL

Cloud SQL es el servicio de bases de datos relacionales totalmente gestionado que utilizamos en HERA. Nos libera de la carga de administrar bases de datos, proporcionando alta disponibilidad (HA), backups automáticos, cifrado integrado y escalabilidad para nuestros motores PostgreSQL y MySQL.


Para nuestras bases de datos de producción, la alta disponibilidad no es opcional. La configuración de HA de Cloud SQL garantiza la resiliencia ante fallos zonales.

Cloud SQL — Alta Disponibilidad
us-central1 — Región Primaria
Primaria
Zone A
Recibe tráfico R/W
Replicación Síncrona
Standby
Zone B
En espera · Failover
Failover automático en menos de 120 segundos ante fallo zonal
Replicación Asíncrona
us-east1 — Región de Disaster Recovery
Réplica de Lectura (Async)
Disaster Recovery Reporting BI
Primaria — Lectura/Escritura activa
Standby — Warm failover sincrónico
Réplica DR — Recuperación asíncrona
Mensaje clave HA regional con failover automático. Réplica standby en zona distinta — recovery en menos de 60 segundos.
  • Instancia Primaria: Atiende todo el tráfico de lectura y escritura.
  • Instancia Standby: Es una copia exacta en una zona diferente. No atiende tráfico, pero está lista para tomar el control si la primaria falla. La replicación es síncrona.
  • Réplica de Lectura: Instancia en otra región para recuperación ante desastres (DR) y para descargar consultas de solo lectura (ej. reportes). La replicación es asíncrona.

Naming de bases de datos y conexión desde servicios

Sección titulada «Naming de bases de datos y conexión desde servicios»

Cada servicio desplegado en GKE o Cloud Functions consume una base de datos lógica dentro de una instancia Cloud SQL compartida. La convención de naming y el modelo de ownership son mandatorios para mantener aislamiento, trazabilidad y auditoría.

Siguiendo los Estándares de Nombramiento en GCP, la base de datos lógica adopta el formato db_<producto>_<servicio> (snake_case) — incluye siempre producto y servicio para garantizar unicidad en instancias compartidas cross-producto (ver Instancias compartidas cross-producto) y evitar renames futuros.

AspectoValorEjemplo
Instancia Cloud SQL (dedicada por producto)sql-<producto>-<motor> (project-scoped)sql-tienda-herdez-postgres
Instancia Cloud SQL (compartida cross-producto)sql-<capability>-<motor> o sql-shared-<motor>sql-sites-externos-postgres
Base de datos lógicadb_<producto>_<servicio> (snake_case obligatorio por compatibilidad con motores SQL)db_tienda_herdez_checkout, db_tienda_herdez_inventory, db_miel_carlota
Usuario SQLEmail del GSA: <gsa>@<gcp-project>.iam (tipo CLOUD_IAM_SERVICE_ACCOUNT)gsa-tienda-herdez-backend-checkout-service@ghdz-grupo-ext-sites-prd.iam
Env var con el nombreDB_<CONTEXT>_NAME (ver Estándares de Configuración R11)DB_CHECKOUT_NAME=db_tienda_herdez_checkout

El producto en el nombre de la DB debe coincidir con el nombre canónico declarado en Estructura de Repositorios. El servicio es la parte <detalle> del deployment (sin el prefijo <tipo>- ni el sufijo -service).

ReglaDetalle
Una base lógica por servicioCada servicio (deployment en GKE o Cloud Function) es dueño de su base de datos lógica. No se comparte la base entre servicios.
Sin acceso cross-databaseUn servicio NO consulta la base de otro servicio directamente — se comunica vía el API del servicio dueño. Rompe acoplamiento y respeta bounded context del dominio.
Instancia compartida, schemas aisladosVarios db_<producto>_<servicio> pueden vivir en la misma instancia Cloud SQL si pertenecen al mismo producto/dominio; la separación lógica al nivel de base + usuario IAM es suficiente para el aislamiento en la práctica.
Schema publicCada db_<producto>_<servicio> usa el schema public por default. No se recomienda subdivisión en schemas adicionales salvo casos justificados (ej. multitenancy dentro del servicio).

Modelo de instancia compartida — múltiples bases lógicas

Sección titulada «Modelo de instancia compartida — múltiples bases lógicas»

Una sola instancia Cloud SQL puede hospedar múltiples bases de datos lógicas, una por servicio. Este es el modelo estándar en HERA por razones de costo (las instancias son caras), gobernanza (simplifica backups, HA, parches) y operación (menos superficie que administrar).

Instancia Cloud SQL: sql-tienda-herdez-postgres
Project: ghdz-grupo-ext-sites-prd
Región: us-central1 (HA zonal + read-replica DR)
├─ db_tienda_herdez_checkout ← backend-checkout-service
│ GSA: gsa-tienda-herdez-backend-checkout-service
├─ db_tienda_herdez_inventory ← backend-inventory-service
│ GSA: gsa-tienda-herdez-backend-inventory-service
├─ db_tienda_herdez_catalog ← backend-catalog-service
│ GSA: gsa-tienda-herdez-backend-catalog-service
└─ db_tienda_herdez_notifications ← platform-notifications-service
GSA: gsa-tienda-herdez-platform-notifications-service
── Recursos compartidos ──
CPU, RAM, disco, max_connections, backups, HA standby, Audit Log
── Aislamiento ──
GRANTs por GSA → cada servicio ve SÓLO su db_<producto>_<servicio>
ReglaDetalle
Por defecto: una instancia por producto/dominioTodos los servicios de un mismo producto comparten instancia. Ej. tienda-herdez/* comparten sql-tienda-herdez-postgres.
Una base lógica por servicioNunca se mezclan 2 servicios en la misma db_<producto>_<servicio>.
Acceso aislado por GSA + GRANTsEl GSA del servicio A no tiene permisos sobre db_b. Se enforce a nivel de GRANT, no sólo de convención.
Sin SUPERUSER en GSAs de aplicaciónSolo el rol DBA dispone de privilegios administrativos sobre la instancia.
Auditoría cuatrimestralDBA revisa GRANTs e inventario instancia → DBs → servicios.

Cuándo NO compartir instancia (criterios de split)

Sección titulada «Cuándo NO compartir instancia (criterios de split)»

Aunque la compartición es el default, hay criterios claros para provisionar una instancia dedicada a uno o pocos servicios:

CriterioJustificaciónEjemplo
Criticidad distintaUn Tier 1 no debe compartir recursos con un Tier 3checkout (Tier 1) vs. admin-reporting (Tier 3) → instancias separadas
Perfil de carga incompatibleOLTP mezclado con analytics/ETL satura CPU e I/Odata-* services en instancia propia
Clase de compliancePCI-CDE debe estar aislado de datos internosCheckout PCI en instancia dedicada con CMEK y Audit Log separado
SLA / HA diferentes99.99% no comparte con best-effort
Límites del motor agotadosmax_connections, shared_buffers, IOPS saturados por el conjunto actualSplit cuando la métrica agregada supera el umbral
Recurso¿Compartido entre bases lógicas?Impacto operacional
CPU / RAM✅ CompartidoQuery lenta en db_A degrada rendimiento de db_B
Disco / IOPS✅ CompartidoBackup pesado ralentiza I/O de todas las DBs
max_connections✅ CompartidoPool excesivo en un servicio agota el pool global
Backup automático + PITR✅ Instance-levelRestore afecta todas las DBs a la vez
HA standby✅ Instance-levelFailover cubre la instancia completa
Cloud Audit Log✅ Instance-levelLogs mezclados; filtrar por resource.labels.database_id
Datos y GRANTsAislado por DBCada GSA ve sólo su db_<producto>_<servicio> — el aislamiento lógico se respeta

La convención sql-<producto>-<motor> asume una instancia por producto, pero HERA opera en la práctica con instancias corporativas compartidas por razones de costo — cada instancia Cloud SQL tiene un mínimo fijo (~US$50/mes en el tier más chico) multiplicado por los 3 ambientes (DEV/QA/PRD), y multiplicar eso por decenas de productos generaría un gasto no justificable para proyectos de bajo volumen.

Cuando una instancia aloja DBs de múltiples productos, el naming de la instancia y el modelo de gobierno cambian ligeramente:

AlcanceFormatoEjemplo
Dedicada a un productosql-<producto>-<motor>sql-tienda-herdez-postgres
Compartida por capability (varios productos del mismo área)sql-<capability>-<motor>sql-sitios-externos-postgres, sql-loyalty-postgres
Corporativa transversal (cualquier producto puede solicitar una DB aquí)sql-shared-<motor>sql-shared-postgres, sql-shared-mysql

Por qué el naming db_<producto>_<servicio> es obligatorio aquí

Sección titulada «Por qué el naming db_<producto>_<servicio> es obligatorio aquí»

En una instancia compartida donde conviven DBs de múltiples productos, omitir el producto en el nombre de la DB provoca colisión inevitable:

Instancia: sql-sitios-externos-postgres (compartida por capability)
├─ db_miel_carlota_cms ← producto: miel-carlota, servicio: cms
├─ db_flaveur_cms ← producto: flaveur, servicio: cms
├─ db_m22_cms ← producto: m22, servicio: cms
├─ db_cholula_cms ← producto: cholula, servicio: cms
└─ db_thepossible_cms ← producto: the-possible, servicio: cms
── Sin producto en el nombre: los 5 productos colisionarían en "db_cms" ──
AspectoRegla en instancia compartida
Ownership de la instanciaPlatform Engineering + DBA. Los productos consumen DBs; no “poseen” la instancia.
Aprovisionamiento de DBsCada producto solicita su db_<producto>_<servicio> vía el módulo IaC grupo-herdez/platform/iac/cloudsql-instance (variable databases = [...]).
Aislamiento de datosdb_<producto>_<servicio> + GSA + GRANTs restringidos por DB. Un GSA de producto A no tiene acceso a db_<producto-b>_*.
Recursos compartidosCPU/RAM/IOPS/max_connections se comparten entre productos — más crítico monitorear “noisy neighbor” cross-producto.
Criterios para forzar instancia dedicadaCriticidad Tier 1, compliance PCI-CDE, alta carga OLTP o límites del motor agotados (mismo set que ya documentado en la sección anterior, pero con más peso cuando hay múltiples productos).
FinOpsEl costo de la instancia compartida se prorratea entre productos vía labels (product, criticality) o se asume como costo de plataforma. La decisión es de la mesa FinOps + Platform.

Inventario y ownership — dónde se declara cada DB

Sección titulada «Inventario y ownership — dónde se declara cada DB»

Para prevenir “DBs huérfanas” (creadas manualmente sin trazabilidad) y habilitar la auditoría automática del DBA, cada base lógica debe declararse en tres artefactos versionados:

ArtefactoDónde viveQué declara
product-manifest.ymlgrupo-herdez/products/<dominio>/<producto>/_shared/Lista de instancias Cloud SQL del producto y las DBs que hospedan
service-manifest.ymlRepo del servicio consumidordatabase.instance y database.name a los que se conecta
Módulo IaC cloudsql-instanceConsumido desde _shared/iac-infra del productoRecibe databases = [...] como variable; crea las DBs e IAM users

El DBA audita cuatrimestralmente que:

  1. Toda DB en la instancia aparece en el módulo IaC (no se crean manualmente).
  2. Toda DB tiene un servicio owner declarado en algún service-manifest.yml.
  3. Los GRANTs activos coinciden con los declarados.

Recap del mapeo pod → DB para servicios desplegados en la plataforma:

PlataformaCómo se conecta el servicio
GKE DeploymentserviceAccountName (KSA) del pod → vinculado al GSA vía Workload Identity → Cloud SQL Auth Proxy sidecar en 127.0.0.1 → IAM DB Auth → db_<producto>_<servicio>. Ver Conexión Segura desde GKE.
Cloud FunctionserviceAccount configurado al deploy (equivale al GSA de GKE) → conexión directa a la IP privada de la instancia con IAM DB Auth habilitada → db_<producto>_<servicio>. No requiere sidecar: el connector nativo de Cloud Functions negocia el token.

En ambos casos:

  • Env vars canónicas DB_<CONTEXT>_HOST/PORT/NAME/USERNAME inyectadas vía ConfigMap (GKE) o variables del deploy (Cloud Function). Ver Estándares de Configuración R11.
  • Nunca hardcoded en la imagen ni en el código.
  • Un servicio = un GSA = un GRANT = una db_<producto>_<servicio> — sin excepciones en PRD.

La forma correcta de conectar una aplicación en GKE a Cloud SQL es utilizando el Cloud SQL Auth Proxy.

Autenticación passwordless con Workload Identity + IAM DB Auth

Sección titulada «Autenticación passwordless con Workload Identity + IAM DB Auth»

En HERA, hemos estandarizado la eliminación de contraseñas estáticas. Para conectar una base de datos de forma segura sin gestionar secretos, implementamos un esquema de dos niveles:

  1. Nivel de Infraestructura (Workload Identity): El pod de la aplicación asume una identidad de Google Cloud (GSA) a través de su Service Account de Kubernetes (KSA). Consulta la Guía de Workload Identity para más detalles.
  2. Nivel de Base de Datos (IAM DB Auth): Cloud SQL se configura para aceptar la identidad del GSA como un usuario de base de datos válido, generando tokens de corta duración en lugar de contraseñas.

1. Habilitar IAM Auth en la instancia

La instancia Cloud SQL debe tener el flag cloudsql.iam_authentication = on. Este flag se declara en el módulo de Terraform de la base de datos — habilita que Cloud SQL valide tokens OAuth 2.0 de identidades GCP en lugar de sólo usuarios SQL tradicionales con password.

AspectoValorJustificación
Flagcloudsql.iam_authenticationAPI oficial de Google Cloud SQL para IAM auth
ValoronActiva validación de tokens GCP en la conexión
Aplica aTodas las instancias PRD y QAElimina credenciales estáticas de la infra

2. Crear el usuario SQL mapeado al Service Account

Por cada servicio que consume la base, se crea un usuario SQL cuyo nombre es el correo del Google Service Account (GSA) y cuyo tipo es CLOUD_IAM_SERVICE_ACCOUNT. Con esto Cloud SQL reconoce los tokens de ese GSA como credenciales válidas.

AspectoValor
Nombre del usuario SQL<nombre-gsa>@<gcp-project>.iam (formato fijo)
Tipo del usuarioCLOUD_IAM_SERVICE_ACCOUNT
PasswordNinguno — se autentica con tokens rotados automáticamente por GCP
Ejemplobackend-checkout-service-prd@hera-prd.iam

3. Otorgar permisos (GRANTs) dentro de la base de datos

El usuario recién creado no tiene permisos por defecto. Un DBA o un job de inicialización del producto debe ejecutar los GRANT específicos. Ejemplo mínimo para una app que lee y escribe en el schema public:

GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA public
TO "<nombre-gsa>@<gcp-project>.iam";

Política HERA de privilegios mínimos:

  • Cada servicio recibe solo los permisos que ejercita su dominio (principio least privilege).
  • Los GRANT ALL están prohibidos en PRD — se declara la lista explícita de operaciones.
  • Los privilegios se auditan cada cuatrimestre como parte de la revisión periódica de accesos (Security Engineer).

Como la autenticación se delega al Auth Proxy y a las credenciales por defecto (ADC), el código no requiere contraseña. Para ambientes de producción, es obligatorio configurar un connection pool con manejo de desconexión.

Node.js (pg)

const { Pool } = require('pg');
// Al usar el Auth Proxy en 127.0.0.1, omitimos el password.
// El proxy negocia el token IAM transparente para la app.
const pool = new Pool({
user: process.env.DB_CHECKOUT_USERNAME, // email del GSA inyectado vía env var
host: process.env.DB_CHECKOUT_HOST, // 127.0.0.1 (sidecar Auth Proxy)
database: process.env.DB_CHECKOUT_NAME, // ej. db_tienda_herdez_checkout
port: Number(process.env.DB_CHECKOUT_PORT), // 5432
// ¡Sin contraseña!
// Configuración de producción para connection pooling
max: 20, // Máximo de conexiones persistentes
idleTimeoutMillis: 30000, // Cierra clientes inactivos después de 30 segundos
connectionTimeoutMillis: 2000, // Retorna error si no se conecta en 2 segundos
});
// Manejo de errores de conexión a nivel de pool para evitar caídas silenciosas
pool.on('error', (err, client) => {
console.error('Error inesperado en cliente inactivo de la base de datos', err);
});

Python (SQLAlchemy)

import os
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
# Variables inyectadas al pod vía env vars (ver Estándares de Configuración R11)
db_user = os.environ["DB_CHECKOUT_USERNAME"] # email del GSA, sin password
db_name = os.environ["DB_CHECKOUT_NAME"] # ej. db_tienda_herdez_checkout
db_host = os.environ["DB_CHECKOUT_HOST"] # 127.0.0.1 (sidecar Auth Proxy)
db_port = os.environ["DB_CHECKOUT_PORT"] # 5432
# Configuración de producción con connection pooling y manejo de desconexión
engine = create_engine(
f"postgresql://{db_user}@{db_host}:{db_port}/{db_name}",
poolclass=QueuePool,
pool_size=5, # Máximo de conexiones persistentes base
max_overflow=10, # Conexiones extra permitidas en picos
pool_timeout=30, # Segundos de espera si el pool está lleno antes de fallar
pool_recycle=1800, # Reciclar conexiones después de 30 minutos
pool_pre_ping=True # Verificar que la conexión sigue viva antes de usarla
)

Desplegamos el proxy como un contenedor “sidecar” en el mismo pod que nuestra aplicación. Utilizamos el flag --auto-iam-authn para que el proxy utilice la identidad del pod (Workload Identity) para solicitar los tokens de base de datos automáticamente. La aplicación se conecta al proxy en 127.0.0.1.

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mi-app
spec:
template:
spec:
serviceAccountName: mi-app-ksa # Imprescindible para Workload Identity
containers:
# --- Contenedor de la aplicación ---
- name: mi-app
image: gcr.io/mi-proyecto/mi-app:v1
env:
- name: DB_HOST
value: "127.0.0.1" # <-- La app apunta a localhost
- name: DB_PORT
value: "5432"
- name: DB_USER
value: "mi-app-gsa@mi-proyecto.iam"
# DB_PASSWORD ha sido eliminado por completo en esquema passwordless
# --- Contenedor Sidecar: Cloud SQL Auth Proxy ---
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
args:
- "--structured-logs"
# Habilita la autenticación con IAM DB Auth usando Workload Identity
- "--auto-iam-authn"
# Nombre de la instancia de conexión
- "mi-proyecto:us-central1:hera-prd-db"
securityContext:
runAsNonRoot: true
resources:
requests:
memory: "256Mi"
cpu: "100m"

Todo cambio al schema de una base de datos (crear tabla, añadir columna, crear índice, eliminar constraint, etc.) debe aplicarse mediante un archivo de migración versionado en Git — igual que el código de aplicación. Este modelo se conoce como Database as Code (DBaC) y es obligatorio en HERA.

Sin DBaCCon DBaC
SQL ad-hoc corrido por un dev contra PRDTodo cambio es un archivo en db/migrations/ con su MR aprobado
Imposible saber quién/cuándo cambió quéAudit trail completo vía git log + historial del tool
No se puede reproducir DEV desde ceromigrate up levanta la DB al estado actual desde el primer commit
Rollbacks manuales, frágilesMigraciones con down.sql o versiones reversibles
Deploy de app + cambio de schema no coordinadosPipeline aplica migrate up antes del deploy nuevo

HERA mantiene una lista cerrada de herramientas de migración por stack tecnológico. No se permite el uso de herramientas fuera de esta lista sin aprobación del DBA.

StackHerramienta estándarAlternativa aprobada
Java / Spring BootFlywayLiquibase
Node.jsnode-pg-migratePrisma Migrate · Knex
PythonAlembic (SQLAlchemy)
Gogolang-migrateAtlas
.NETEF Core Migrations
PHPDoctrine MigrationsPhinx

Los archivos de migración viven en un directorio dedicado del repo del servicio:

backend-checkout-service/
├── src/
├── db/
│ ├── migrations/
│ │ ├── V001__create_orders_table.sql
│ │ ├── V002__add_status_index.sql
│ │ └── V003__add_customer_email.sql
│ └── seeds/
│ └── reference_data.sql
├── Dockerfile
└── service-manifest.yml

Reglas:

  • Prefijo de versión monótono (V001, V002, …) o timestamp (20260421_120000) según la convención del tool elegido.
  • Un cambio por archivo — no agrupar CREATE TABLE + CREATE INDEX si son conceptualmente distintos.
  • Archivos nunca se modifican una vez mergeados a main. Corrección de un error se hace con una migración nueva que revierte/ajusta.
  • seeds/ solo para datos de referencia no sensibles (catálogos, tipos enum). Datos de usuario NO van aquí.

El Golden Pipeline incluye un stage pre-deploy que aplica las migraciones pendientes antes de desplegar la nueva versión de la aplicación.

JobStageAcciónCondición de fallo
db-migratepre-deploy<tool> migrate up sobre la instancia Cloud SQL del ambiente (DEV/QA/PRD)Migration falla → el deploy de la app no corre → app sigue en la versión anterior

Esto garantiza que la versión nueva de la app nunca corra sobre un schema desactualizado (ni al revés). Si la migration falla en QA/PRD, el deploy se cancela y el equipo remedia antes de reintentar.

Anti-patternPor quéQué hacer en su lugar
ALTER TABLE ejecutado manualmente desde psql/mysql contra PRDRompe audit trail y genera drift entre repo y DB realAbrir MR con archivo de migración
DROP COLUMN/DROP TABLE sin aprobación explícita del DBARiesgo de pérdida de datos no reversibleMR con label schema-breaking-change + review obligatorio del DBA
❌ Modificar un archivo de migration ya mergeadoRompe la reproducibilidad: DEV y PRD quedan con historias distintasNueva migration que corrija o revierta
❌ Usar ORM auto-migration en PRD (ej. hibernate.ddl-auto=update)Cambios opacos sin revisión — el schema deriva sin trazabilidadORM en modo validate o none; schema evoluciona solo vía migrations explícitas
❌ Migraciones que toman locks largos en tablas grandes en PRDRiesgo de downtime/lock contentionCoordinar con DBA+SRE · usar estrategias online (CREATE INDEX CONCURRENTLY, pt-osc, gh-ost)
ActividadResponsable (R)Aprobador (A)Consultado (C)
Diseñar schema inicial de un servicioTech Lead + DBADBAArquitecto
Redactar migration ADD COLUMN no-breakingDeveloperTech LeadDBA
Redactar migration con breaking change (DROP, RENAME, type change)DeveloperDBA (obligatorio)Tech Lead + SRE
Migration con riesgo de lock en tabla grande PRDDeveloperDBA + SRETech Lead
Ejecutar migration en PRDPipeline (db-migrate job)DBA (si breaking change)
Auditar historial de migrationsDBA (cuatrimestral)Security Engineer

Nuestra estrategia de backups está diseñada para recuperarnos de cualquier tipo de desastre, desde un DELETE accidental hasta un fallo regional.

TipoFrecuenciaRetención (PRD)Caso de Uso
Backup AutomáticoDiario (3 AM)30 díasRecuperación completa de la instancia.
PITR (Point-in-Time)Continuo (Logs)7 díasRecuperación granular. Restaurar la base a un estado exacto, al segundo. Ideal para errores humanos.
Backup On-demandManualHasta eliminaciónRealizado antes de cambios críticos como migraciones de esquema.
ExportSemanal90 días en GCSCreación de una copia lógica para archivado o para cargar en otros sistemas (ej. BigQuery).
  • Restaurar un backup: Crea una nueva instancia a partir de un backup específico.
    Ventana de terminal
    gcloud sql backups restore BACKUP_ID --restore-instance=nueva-instancia-clone
  • Restaurar a un punto en el tiempo (PITR): Clona la instancia a un momento exacto. Es la herramienta más potente contra errores.
    Ventana de terminal
    gcloud sql instances clone hera-prd-db hera-prd-db-recuperada \
    --point-in-time="2024-01-15T10:30:00Z"

ControlConfiguración en HERAEstado
Cifrado en TránsitoSSL/TLS gestionado por el Auth Proxy.
Cifrado en ReposoCifrado por defecto por Google. Usamos CMEK (Customer-Managed Keys) para datos sensibles.
Acceso a la RedIP Privada únicamente. No se exponen IPs públicas.
AutenticaciónAutenticación de base de datos de IAM. Los usuarios y SAs de IAM pueden autenticarse sin contraseña.
AuditoríaCloud Audit Logging habilitado para todas las operaciones administrativas y de acceso a datos.

Query Insights es una herramienta indispensable para el diagnóstico de rendimiento de la base de datos. Nos ofrece una vista detallada de las consultas más lentas y que más recursos consumen.

Métrica claveUmbral de alerta (PRD)Severidad
Utilización de CPU> 80% por 15 minAlta
Utilización de Memoria> 90% por 10 minAlta
Utilización de Disco> 85%Crítica
Retraso de Replicación> 30 segundosMedia
Conexiones activas> 80% del máximoMedia

Con Query Insights, podemos identificar rápidamente consultas problemáticas y recibir recomendaciones, como la creación de un índice, para optimizarlas.

-- Query Insights detecta esta consulta como Top Consumer (Seq Scan completo)
EXPLAIN ANALYZE
SELECT o.id, o.total, c.email
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.status = 'pending'
ORDER BY o.created_at DESC;
-- Resultado: Seq Scan on orders (cost=0.00..9240.00 rows=85000)
-- Filter: (status = 'pending')
-- Rows removed by filter: 164823
-- Recomendación de Query Insights: índice compuesto en (status, created_at)
CREATE INDEX CONCURRENTLY idx_orders_status_date
ON orders (status, created_at DESC);
-- Resultado post-optimización: Index Scan (cost=0.43..12.30 rows=3)
-- Mejora: de 9 segundos a menos de 50 ms en tabla de 250K filas