BookinglyTech News
Infraestructura

PostgreSQL frente a MySQL: diferencias de motor y cuándo importan

Los dos motores resuelven la concurrencia de forma distinta: versiones de fila en el heap frente a un undo log separado. La elección depende del perfil de carga, no de la lista de características.

3 min de lecturaDev.to0 vistas

Elegir motor de base de datos repasando una lista de características es una manera cara de llegar a un incidente en producción. Un análisis técnico sobre PostgreSQL e InnoDB defiende que la decisión debe salir del perfil de carga —ratio de lectura y escritura, complejidad transaccional, patrones de consulta, profundidad de las relaciones, latencia de cola p99— y no de la costumbre del equipo ni de comparativas de folleto.

El trabajo empieza en la carga

El texto descompone la carga en cinco ejes: si dominan las lecturas puntuales, los range scans, las inserciones masivas o las actualizaciones complejas; qué niveles de aislamiento y atomicidad entre tablas hacen falta; cómo de predecibles son los predicados y hasta dónde llega la selectividad de los índices; cuántos saltos tienen las claves foráneas y si hay esquemas semiestructurados; y cuánta contención de hilos y saturación de conexiones aguanta el sistema. Un ratio desequilibrado de escrituras no duele igual en cada motor, porque la amplificación de escritura y el mantenimiento en segundo plano se acaban pagando.

PostgreSQL: un proceso por conexión

El postmaster lanza un proceso por cada cliente. Esa separación aísla la memoria compartida: si un backend se cae, no arrastra a los vecinos ni corrompe el estado global. Las páginas de datos, de 8 KB por defecto, viven en los shared buffers, y toda modificación pasa antes por el WAL, un log binario de solo append. El MVCC guarda varias versiones físicas de cada fila dentro de las páginas del heap, con marcas xmin y xmax en la cabecera. Para que eso no se descontrole están el checkpointer, el background writer, el wal writer y el autovacuum, que barre tuplas muertas y evita el wraparound de identificadores de transacción. El planificador es cost-based y los índices van de B-tree a BRIN, GIN o GiST, con extensiones como PostGIS o pgvector.

InnoDB: un proceso, muchos hilos

MySQL delega en el motor de almacenamiento, y en producción eso significa InnoDB. Aquí todo corre en hilos dentro de un único proceso. El buffer pool guarda páginas de 16 KB y usa una variante de LRU partida en dos sublistas para que un full scan no expulse el working set caliente. La durabilidad la da el redo log, circular y de tamaño fijo, mientras que las versiones antiguas de fila van a un undo log en segmentos aparte. Cada tabla se organiza alrededor de su clave primaria: las hojas del índice clustered contienen la fila y los índices secundarios apuntan al valor de esa clave. Los page cleaner vuelcan páginas sucias con algoritmos adaptativos, y el bloqueo es granular, con record locks, gap locks y next-key locks.

Donde se separan de verdad

Las transacciones largas son el punto de fricción. En PostgreSQL generan bloat y bloquean al vacuum a la hora de recuperar ese espacio; en InnoDB inflan los segmentos de rollback. Actualizar una fila en PostgreSQL escribe una versión nueva del tuple en el heap y los índices apuntan a TIDs; en InnoDB, tocar un índice secundario obliga a resolver antes la clave primaria. La limpieza también cambia de forma: autovacuum recorre tablas e índices enteros, y los hilos de purge retiran registros de undo que ya nadie necesita.

Ninguno de los dos motores es mejor en abstracto. Un sistema que mezcla analítica con tráfico transaccional y arrastra transacciones largas sufre en PostgreSQL por bloat y vacuum, y en InnoDB lo paga con undo log que crece sin control. Lo que queda por delante es medir la carga real antes de decidir la migración, no después.