Tema: databases
-
Mantener visibles los límites de la transacción
Documentar qué cambios de estado se confirman juntos y qué puede ocurrir entre las transacciones de base de datos y las llamadas externas.
-
Búsqueda de texto completo en PostgreSQL con tsvector
PostgreSQL convierte el texto en un tsvector de lexemas normalizados usando una configuración de idioma, lo compara con tsquery, lo clasifica con ts_rank y lo indexa con GIN; gestiona la derivación de raíces (stemming) y las palabras vacías, pero no las erratas ni los sinónimos de forma nativa.
-
Event sourcing y CQRS: qué se gana y qué cuesta
Event sourcing almacena cada cambio de estado como un evento inmutable y obtiene el estado actual reproduciéndolos; CQRS separa el modelo de escritura de los modelos de lectura. Ambos añaden capacidad de auditoría y flexibilidad al precio de mayor complejidad y de consistencia eventual.
-
Gestión de extensiones de PostgreSQL: instalación, versionado, actualización y volcado
Una extensión empaqueta objetos SQL y, a menudo, una biblioteca compartida bajo un único nombre, con un archivo de control y scripts versionados; CREATE EXTENSION la instala por base de datos, ALTER EXTENSION UPDATE aplica los scripts de actualización de quien la desarrolla, y pg_dump solo emite la línea CREATE EXTENSION. Es necesario mantener sincronizados los archivos instalados, la versión del catálogo y la biblioteca cargada, especialmente entre actualizaciones de paquetes y con pg_upgrade.
-
Datos semilla y fixtures para bases de datos locales: pequeños, idempotentes y versionados junto con el esquema
Separar los datos de referencia (necesarios en todas partes), los datos de ejemplo (para desarrollo y demostraciones) y los datos de prueba (creados por los propios tests); escribir la siembra como código idempotente con upserts sobre claves naturales, mantener el conjunto de ejemplo pequeño y nombrado, ejecutarla después de las migraciones tanto en el script de configuración como en la integración continua, y no sembrar nunca las máquinas de desarrollo con datos de producción sin anonimizar.
-
Diseñar una tabla de series temporales de solo inserción en PostgreSQL
Almacenar las mediciones en una tabla particionada por rango de tiempo con timestamptz, una clave compuesta de serie y tiempo, índices ajustados al patrón de consulta (B-tree por serie, BRIN para recorridos de tiempo sobre toda la tabla) y una retención implementada separando y eliminando particiones en lugar de usar DELETE; estas decisiones se derivan de que las filas llegan en orden temporal y se eliminan en bloques temporales completos.
-
Almacenar datos derivados en PostgreSQL: columnas generadas frente a vistas materializadas
Una columna generada deriva un valor por fila a partir únicamente de esa fila, ya sea de forma virtual (calculada en la lectura) o almacenada (calculada en la escritura), y solo puede usar expresiones inmutables; una vista materializada almacena el resultado de cualquier consulta y está tan actualizada como su último REFRESH. Conviene usar columnas generadas almacenadas para la normalización por fila que deba indexarse, vistas materializadas para agregados costosos que puedan quedar desactualizados, y una tabla de resumen mantenida al día cuando ninguna de las dos encaja.
-
VACUUM, autovacuum y la hinchazón de las tablas
El control de concurrencia multiversión (MVCC) de PostgreSQL deja versiones de filas muertas tras las actualizaciones y las eliminaciones; VACUUM las recupera y mantiene las estadísticas y la protección contra el desbordamiento del identificador de transacción. El autovacuum debe permanecer activado y ajustarse para las tablas con mucha actividad.
-
Bases de datos efímeras en contenedores para pruebas de integración
Iniciar el motor de base de datos real en un contenedor desechable por cada ejecución de pruebas, mantener sus datos en memoria, aplicar las migraciones una sola vez a una base de datos plantilla y copiarla por cada archivo de pruebas; así las pruebas ejercitan el planificador real, las restricciones y el comportamiento de aislamiento en lugar de un sustituto en memoria.
-
Niveles de aislamiento de transacciones en la práctica
Read committed, repeatable read y serializable intercambian concurrencia por coherencia; saber qué anomalías permite cada nivel determina cuándo añadir bloqueos explícitos o reintentos.
-
Cambios en la base de datos sin interrupción: expandir y contraer
Modificar un esquema en tres pasos desplegables por separado: expandir (crear una columna o tabla nueva y conservar la antigua), migrar (escribir por duplicado y rellenar en lotes pequeños), contraer (eliminar lo antiguo en cuanto todo el código use lo nuevo); evitar bloqueos largos no reescribiendo ninguna tabla en una sola sentencia, y limitando toda espera con lock_timeout.
-
Datos de prueba sin datos personales de producción
Dar a desarrollo, CI y staging datos realistas generándolos: clasificar las columnas, escribir generadores con semilla que pasen los validadores de la aplicación, producir volumen con generate_series, copiar de producción solo las distribuciones, marcar los registros generados de forma reconocible, y eliminar el atajo de volcar producción.
-
NULL en SQL: la lógica trivalente y sus trampas
NULL significa desconocido, así que las comparaciones con NULL producen desconocido en lugar de verdadero o falso; los filtros WHERE descartan las filas con resultado desconocido, NOT IN con un NULL no encuentra nada, y las funciones de agregación omiten los NULL. Usar IS NULL, IS DISTINCT FROM y COALESCE de forma deliberada.
-
Modo de mantenimiento de solo lectura: servir lecturas mientras las escrituras están pausadas
Para traslados de almacenamiento, conmutaciones por error y migraciones largas, un servicio puede seguir sirviendo lecturas y rechazar las escrituras con un mensaje claro en lugar de quedar fuera de servicio; default_transaction_read_only de PostgreSQL hace de las nuevas transacciones transacciones de solo lectura a nivel de base de datos como respaldo, y el 503 de HTTP con Retry-After indica a los clientes cuándo volver a intentarlo. El modo necesita un único interruptor, un mensaje visible para los usuarios y un ensayo.
-
Expresiones de tabla común y consultas recursivas con WITH
WITH nombra una subconsulta para el resto de una sentencia; WITH RECURSIVE evalúa un término no recursivo y luego repite un término recursivo hasta que este no produce filas nuevas, lo que permite recorrer árboles y grafos de cualquier profundidad en una sola consulta. Las CTE de un solo uso y sin efectos secundarios se integran en la consulta externa a menos que se escriba MATERIALIZED, y las cláusulas SEARCH y CYCLE gestionan el orden y los bucles.
-
Columnas JSONB: para qué sirven y cuándo es mejor una columna
jsonb almacena JSON analizado en una forma binaria que puede indexarse con GIN y consultarse con operadores de contención y de ruta; conviene a atributos dispersos, definidos externamente o realmente variables. Los datos con una forma fija, los datos que necesitan restricciones, claves foráneas o actualizaciones por campo, y los documentos grandes que cambian con frecuencia, pertenecen a columnas ordinarias.
-
Prevenir la inyección SQL con consultas parametrizadas
Nunca construir SQL concatenando cadenas no confiables; pasar los valores como parámetros para que el controlador (driver) los envíe por separado de la sentencia, y usar una lista de permitidos para cualquier identificador que deba ser dinámico.
-
La agrupación de conexiones de base de datos y sus límites
Cada conexión de PostgreSQL es un proceso con un costo de memoria; las aplicaciones deben mantener un grupo (pool) pequeño, dimensionado según la concurrencia real, establecer tiempos de espera de adquisición, y no permitir nunca que los manejadores de solicitudes abran conexiones ad hoc.
-
Reclamos de PostgreSQL SKIP LOCKED medidos con cuatro consumidores concurrentes de una cola
Cuatro transacciones concurrentes reclamaron 25 trabajos sintéticos cada una en PostgreSQL 16.15. Los 100 ID devueltos eran únicos y no quedó ningún trabajo sin reclamar; esto verifica una fase de reclamo acotada, no un procesamiento exactamente una vez ni la sustitución de un bróker.
-
Sagas: flujos de trabajo de varios pasos entre servicios con compensación en lugar de rollback
Una saga es una secuencia de transacciones locales en distintos servicios, cada una desencadenando la siguiente; si un paso falla, los pasos anteriores se deshacen mediante transacciones de compensación que escribe quien desarrolla. Las sagas restauran la consistencia sin transacciones distribuidas, pero renuncian al aislamiento, de modo que los estados intermedios son visibles y las compensaciones deben diseñarse, no darse por supuestas.
Legible por máquina: JSON