4 puntos por GN⁺ 2024-10-21 | 1 comentarios | Compartir por WhatsApp
  • PostgreSQL se ha convertido recientemente en una especie de opción predeterminada de Internet, pero según la experiencia de Carnegie Mellon y OtterTune, su implementación de MVCC implica una mayor carga operativa que MySQL, Oracle y Microsoft SQL Server
  • Su diseño central combina un almacenamiento append-only que no sobrescribe la fila existente al actualizarla, sino que crea una nueva versión física, con una cadena O2N que va de las versiones antiguas a las nuevas
  • Esta estructura deriva en copias completas de tuplas, acumulación de dead tuples, actualización de todos los índices y dependencia de autovacuum; solo cuando es posible una actualización HOT se puede evitar parte del costo
  • En un análisis de bases PostgreSQL de clientes de OtterTune, en promedio solo alrededor del 46% de las actualizaciones usaron la optimización HOT, y la configuración predeterminada de autovacuum puede demorar mucho la limpieza en tablas grandes
  • PostgreSQL sigue siendo un DBMS atractivo, pero en cargas con muchas escrituras y tablas grandes hay que gestionar directamente el espacio de almacenamiento, I/O, memoria, mantenimiento de índices y operación de vacuum

Por qué el MVCC de PostgreSQL es problemático

  • Hay muchísimas opciones de bases de datos —897 registradas en DBDB a abril de 2023—, pero en cada época hubo una opción predeterminada de facto
    • En los años 2000, MySQL, usado por Google y Facebook, era la elección habitual
    • En los años 2010, MongoDB llamó la atención con su imagen de “webscale”
    • En los últimos 5 años, PostgreSQL ha sido ampliamente preferido por su estabilidad, riqueza de funciones, extensibilidad y adecuación a cargas operativas
  • El foco del artículo es la implementación de control de concurrencia multiversión (MVCC) de PostgreSQL
    • Según investigaciones de Carnegie Mellon y la experiencia optimizando Amazon RDS PostgreSQL, la implementación de MVCC de PostgreSQL se considera peor que las de MySQL, Oracle y Microsoft SQL Server
    • Amazon Aurora PostgreSQL tiene los mismos problemas estructurales

Objetivo de MVCC y decisiones de diseño de PostgreSQL

  • MVCC es una técnica para permitir que varias consultas lean y escriban la base de datos al mismo tiempo, en lo posible sin interferirse entre sí
    • El DBMS no sobrescribe filas existentes, sino que mantiene varias versiones físicas por cada fila lógica
    • Una consulta lee la versión que le corresponde según el orden de versiones, como el momento de creación
    • Esto permite aislamiento por snapshot, donde se ve una instantánea de la base de datos del momento en que comienza la transacción
  • Las operaciones de lectura pueden reducir las situaciones en que quedan bloqueadas por locks explícitos de registros debido a escrituras que actualizan el mismo elemento
  • Un DBMS con MVCC debe decidir principalmente tres cosas
    • Cómo almacenar las actualizaciones de una fila existente
    • Cómo encontrar, en tiempo de ejecución, la versión de la fila adecuada para una consulta
    • Cómo eliminar versiones expiradas que ya no son visibles
  • Debido a la primera decisión que PostgreSQL tomó en los años 80, aún hoy arrastra costos en las otras dos áreas

Almacenamiento de versiones append-only

  • PostgreSQL fue diseñado desde el inicio para soportar múltiples versiones y, al actualizar, no sobrescribe la fila existente: crea una copia y aplica los cambios en la nueva versión
  • Este enfoque puede verse como almacenamiento de versiones append-only
    • Al actualizar una tupla existente, el DBMS reserva un slot vacío para la nueva versión de la fila en la tabla
    • Copia el contenido de la fila de la versión actual a la nueva versión
    • Aplica los cambios en el slot recién asignado para la versión
  • La tabla de ejemplo es movies, que contiene información de películas
    • id es la clave primaria y tiene las columnas name, year, director
    • Cuenta con el índice primario movies_pkey y los índices secundarios B+Tree idx_name e idx_director
  • En una actualización que cambia el año de estreno de "Shaolin and Wu Tang" de 1985 a 1983, se copia la tupla original y luego se aplica el año modificado en la nueva versión
    • Si no hay espacio en la página existente, la nueva versión puede crearse en otra página de la tabla

Cadenas de versiones y enfoque O2N

  • Cuando varias versiones físicas representan la misma fila lógica, el DBMS debe registrar la relación entre versiones
    • Un DBMS con MVCC crea una cadena de versiones como una lista enlazada unidireccional
    • La cadena se mantiene en una sola dirección para reducir espacio de almacenamiento y costos de mantenimiento
  • Hay dos órdenes posibles para la cadena de versiones
    • N2O: la versión más nueva apunta a la anterior, y la cabeza de la cadena siempre es la versión más reciente
    • O2N: cada versión apunta a la nueva versión, y la cabeza de la cadena es la versión más antigua
  • La mayoría de los DBMS, incluidos Oracle y MySQL, implementan N2O
  • PostgreSQL, salvo por el motor In-Memory OLTP de Microsoft SQL Server, usa el poco común enfoque O2N
    • O2N puede reducir la necesidad de actualizar los índices para que apunten a la nueva versión cada vez que se modifica una tupla
    • A cambio, puede ser necesario recorrer una larga cadena de versiones para encontrar la versión más reciente
  • El campo t_tcid del header de fila de PostgreSQL contiene el ID de tupla de la siguiente versión o, si es la versión más reciente, el ID de tupla de sí misma
    • Si un índice apunta a una versión antigua, PostgreSQL debe seguir la cadena para encontrar la versión nueva

Cómo se reduce el recorrido de cadenas mediante índices

  • Los desarrolladores de PostgreSQL conocían desde el inicio dos costos
    • El costo de crear una nueva copia de la tupla completa en cada actualización es alto
    • Es un desperdicio que la mayoría de las consultas deban recorrer toda la cadena de versiones para encontrar la versión más reciente que buscan
  • Para evitar recorridos de cadenas largas, PostgreSQL agrega entradas de índice de tabla por cada versión física de una fila
    • Si una fila lógica tiene 5 versiones físicas, puede haber hasta 5 entradas de índice para esa tupla
    • Si el índice idx_name apunta a varias versiones de "Shaolin and Wu Tang", PostgreSQL puede acceder directamente a la versión más reciente
  • El acceso a la versión más reciente puede volverse más rápido, pero los índices crecen y aumenta el costo de mantenimiento

Optimización de actualizaciones HOT

  • PostgreSQL usa actualizaciones HOT (heap-only tuple) para reducir situaciones en las que las versiones relacionadas quedan dispersas en varias páginas y se generan múltiples entradas de índice
  • Hay dos condiciones para que una actualización HOT sea posible
    • La actualización no modifica columnas referenciadas por los índices de la tabla
    • Hay suficiente espacio para guardar la nueva versión en la misma página de datos que la versión anterior
  • Cuando se aplica HOT, el índice sigue apuntando a una versión antigua, y la consulta sigue la cadena de versiones para encontrar la versión más reciente
  • PostgreSQL también realiza una optimización durante la operación normal para podar la cadena de versiones eliminando versiones antiguas

Eliminación de dead tuples y vacuum

  • Como PostgreSQL crea copias de filas en cada actualización, debe eliminar las versiones antiguas, llamadas dead tuples
  • Las primeras versiones de PostgreSQL de los años 80 no eliminaban dead tuples
    • La idea era que conservar versiones antiguas permitiría ejecutar consultas time-travel para ver el estado de la base de datos en un momento específico
    • Pero si no se eliminan dead tuples, el tamaño de la tabla no se reduce aunque haya eliminaciones, y las cadenas de versiones de tuplas actualizadas con frecuencia se alargan
  • PostgreSQL limpia los dead tuples de una tabla mediante el procedimiento vacuum
    • vacuum hace un escaneo secuencial de las páginas de tabla modificadas desde la última ejecución y busca versiones expiradas
    • Si una versión no es visible para ninguna transacción activa, se considera expired
    • Como la transacción actual no accede a esa versión y las transacciones futuras usarán la versión live más reciente, reutilizar el espacio es seguro
  • Según la configuración, PostgreSQL ejecuta autovacuum automáticamente de forma periódica
    • La configuración global permite ajustar la frecuencia de vacuum para todas las tablas
    • También es posible configurar autovacuum por tabla
    • Los usuarios pueden ejecutarlo manualmente con el comando SQL VACUUM

Problema 1: copia completa de tuplas

  • En MVCC append-only, aunque solo cambie una columna de una tupla, todas las columnas se copian en una nueva versión
  • Este enfoque aumenta mucho la duplicación de datos y los requisitos de almacenamiento
    • PostgreSQL puede requerir más memoria y disco que otros DBMS para almacenar la misma base de datos
    • Como resultado, las consultas pueden volverse más lentas y los costos de nube pueden aumentar
  • MySQL y Oracle almacenan deltas comprimidos entre la nueva versión y la versión actual
    • En una tabla con 1000 columnas, si solo cambia una columna, solo se almacena un registro delta para esa columna modificada
    • PostgreSQL crea una nueva versión que contiene la columna modificada y las 999 columnas no modificadas
  • Los atributos TOAST de PostgreSQL se manejan de forma distinta, por lo que se excluyen de esta comparación
  • En 2013, EnterpriseDB inició el proyecto zheap para cambiar el motor de almacenamiento append-only a uno basado en versiones delta
    • La última actualización oficial es un artículo de estado de 2021
    • Desde entonces no se observan avances claros

Problema 2: bloat de tablas

  • Las versiones expiradas de PostgreSQL, es decir, los dead tuples, ocupan más espacio que las versiones delta
  • En cargas write-heavy, los dead tuples pueden acumularse más rápido de lo que autovacuum puede seguir el ritmo
    • La tabla puede seguir creciendo
    • Como los dead tuples y los live tuples están mezclados dentro de las páginas, durante la ejecución de consultas también hay que cargar dead tuples en memoria
    • El bloat no controlado hace que los escaneos de tabla consuman más IOPS y memoria, lo que reduce el rendimiento de las consultas
    • Si los dead tuples vuelven imprecisas las estadísticas del optimizador, pueden derivar en malos planes de consulta
  • Por ejemplo, si la tabla movies tiene 10 millones de live tuples y 40 millones de dead tuples, el 80% son datos obsolete
    • Si el tamaño promedio de una tupla es 1 KB, los live tuples ocupan 10 GB y los dead tuples unos 40 GB
    • El tamaño total de la tabla es 50 GB
    • En un escaneo completo de tabla, PostgreSQL debe leer 50 GB desde disco y cargarlos en memoria, aunque la mayor parte sean datos obsolete
  • PostgreSQL tiene mecanismos de protección para evitar que los escaneos secuenciales contaminen la caché del buffer pool, pero no eliminan el costo de I/O en sí

Diferencia entre VACUUM y VACUUM FULL

  • Aunque autovacuum se ejecute regularmente y siga el ritmo de la carga, el autovacuum normal no puede devolver el espacio de almacenamiento al sistema operativo
  • Un VACUUM normal elimina dead tuples y reubica live tuples dentro de cada página, pero no recupera las páginas vacías del disco
  • Si PostgreSQL puede vaciar la última página, puede truncarla, pero las demás páginas permanecen en disco
    • Incluso si se eliminan 40 GB de dead tuples de una tabla de 50 GB, PostgreSQL puede mantener 50 GB de espacio asignado desde el punto de vista del sistema operativo o de RDS
  • Para devolver realmente el espacio no usado, hay que reescribir toda la tabla en un espacio nuevo con VACUUM FULL o pg_repack
    • Ambas operaciones consumen muchos recursos y tardan bastante
    • En bases de datos de producción, pueden afectar mucho el rendimiento de las consultas
  • VACUUM FULL elimina los dead tuples de cada página, comprime y mueve los live tuples restantes a páginas nuevas, y luego elimina las páginas innecesarias

Problema 3: mantenimiento de índices secundarios

  • PostgreSQL debe actualizar todos los índices de la tabla al actualizar una sola tupla
  • Esto se debe a que tanto los índices primarios como los secundarios almacenan la ubicación física exacta de la versión
    • Si no es una actualización HOT donde la nueva versión queda almacenada en la misma página que la anterior, este trabajo es necesario en cada actualización
  • En la actualización de ejemplo, PostgreSQL crea la nueva versión en Table Page #2 y luego inserta entradas que apuntan a la nueva versión en movies_pkey, idx_director e idx_name
  • Una estructura que obliga a modificar todos los índices genera varios costos de rendimiento
    • Las consultas de actualización se vuelven más lentas
    • Se genera I/O adicional para recorrer cada índice e insertar nuevas entradas
    • Aparece contención de lock/latch en estructuras internas como los índices y las tablas de páginas del buffer pool
    • También se paga costo de mantenimiento en índices que las consultas reales no usan
    • En DBMS con cobro por IOPS, como Amazon Aurora, las lecturas y escrituras adicionales son un problema
  • En un análisis de bases PostgreSQL de clientes de OtterTune, en promedio alrededor del 46% de las actualizaciones usaban la optimización HOT
    • Más del 50% restante de las actualizaciones cargaba con el costo de mantenimiento de índices
  • El artículo de Uber de 2016 sobre su migración de Postgres a MySQL es un caso representativo que muestra este problema
    • Una carga write-heavy sobre tablas con muchos índices secundarios sufrió grandes problemas de rendimiento
  • Oracle y MySQL no tienen el mismo problema porque los índices secundarios no almacenan la dirección física de la nueva versión
    • Los índices secundarios almacenan un identificador lógico, como el ID de tupla o la clave primaria
    • El DBMS usa ese identificador lógico para encontrar la dirección física de la versión actual
    • Las lecturas por índice secundario pueden volverse más lentas, pero otros beneficios de la implementación de MVCC reducen el overhead

Problema 4: dificultad operativa de autovacuum

  • El rendimiento de PostgreSQL depende en gran medida de la efectividad de autovacuum para eliminar datos obsolete y permitir reutilizar espacio
  • RDS, Aurora y Aurora Serverless son variantes de PostgreSQL, por lo que tienen los mismos problemas de autovacuum
  • autovacuum es complejo y difícil de ejecutar en condiciones óptimas
    • La configuración predeterminada no sirve para todas las tablas
    • El problema se agrava especialmente en tablas grandes
  • El valor predeterminado de autovacuum_vacuum_scale_factor es 20%
    • En una tabla de 100 millones de tuplas, al menos 20 millones de tuplas deben actualizarse para que se dispare autovacuum
    • Por eso muchos dead tuples pueden permanecer mucho tiempo en la tabla, generando costos de I/O y memoria
  • Las transacciones de larga duración pueden bloquear autovacuum
    • Si se retrasa la limpieza de expired versions, se acumulan dead tuples y estadísticas viejas
    • Puede formarse un círculo vicioso en el que los problemas de rendimiento generan más transacciones de larga duración, y esas transacciones vuelven a bloquear autovacuum
    • En estos casos, una persona puede tener que terminar manualmente las transacciones de larga duración

Casos de clientes de OtterTune

  • En una base PostgreSQL sobre Amazon RDS, la cantidad de dead tuples varió con forma de dientes de sierra durante dos semanas
    • autovacuum realizaba una limpieza grande aproximadamente una vez al día
    • El 14 de febrero, el DBMS limpió 3.2 millones de dead tuples
    • En el gráfico completo, la cantidad de dead tuples mostraba una tendencia creciente, un estado anormal en el que autovacuum no lograba seguir el ritmo
  • En una instancia PostgreSQL RDS de un cliente de OtterTune, una bulk insertion generó una long-running query debido a estadísticas obsoletas
    • Esa consulta bloqueó la actualización de estadísticas de autovacuum
    • Como resultado, aparecieron más long-running queries
    • El health check automático de OtterTune identificó el problema, pero el administrador tuvo que terminar la consulta manualmente y ejecutar ANALYZE después de la bulk insertion
    • El tiempo de ejecución de esa long query bajó de 52 minutos a 34 segundos

Conclusión práctica

  • En el diseño de DBMS siempre hay decisiones difíciles, y el rendimiento por tipo de carga varía según esas decisiones
  • En una carga específica write-intensive de Uber, la amplificación de escrituras en índices causada por el MVCC de PostgreSQL fue el motivo para migrar a MySQL
  • La implementación de MVCC de PostgreSQL se considera un enfoque que no debería seguirse si se creara un nuevo DBMS con MVCC
    • La combinación de almacenamiento append-only y autovacuum es el problema central
    • Este diseño es un legado de los años 80, previo a la adopción generalizada de patrones de sistemas log-structured desde los años 90
  • PostgreSQL sigue siendo un DBMS preferido, pero hay que operarlo aceptando las debilidades de su MVCC
  • La forma de rodear el problema es invertir mucho tiempo y esfuerzo en tuning manual

1 comentarios

 
GN⁺ 2024-10-21
Opiniones en Hacker News
  • Pensaba que conocía bastante bien las entrañas de Postgres, pero este artículo fue excelente y aprendí mucho.
    Una de sus debilidades fundamentales parece ser que Postgres eligió un enfoque O2N, no N2O, para el seguimiento de versiones de filas. Cambiar a N2O no resolvería todos los problemas; por ejemplo, seguiría quedando el problema de almacenar copias completas de las filas, pero desde una perspectiva 80/20 parece que podría reducir la mayoría de las desventajas de la implementación actual.
    Como la mayoría de las transacciones querrán la versión más reciente de una fila, al usar el orden N2O solo habría que recorrer la lista enlazada cuando se necesite una versión antigua, y es muy probable que no hiciera falta almacenar cada versión de fila en los índices.

    • Vale la pena ver la clase de YouTube de Andy, History of Databases (CMU Databases / Spring 2020).
      Da toda la primera clase en las calles de Ámsterdam porque no pudo entrar al hotel; además de ser un personaje interesante, tiene una capacidad increíble para explicar el funcionamiento interno.
  • Una gran ventaja es que, cuando la carga de trabajo consiste principalmente en INSERT y luego eliminar tablas, no se necesita espacio adicional.
    Por lo general, tampoco hace falta dividir la transacción de inserción. Esto se debe a que no hay un límite práctico en el tamaño de los datos generados ni en el número total de filas modificadas. Hay un límite en la cantidad de sentencias dentro de una transacción, pero si no cambias tablas con demasiada frecuencia, se puede evitar con COPY FROM.
    Desde el punto de vista de un DBA, no hace falta administrar el espacio de rollback/undo por separado del almacenamiento de tablas. Depende de la aplicación, pero el diseño de PostgreSQL no es un perdedor en todos los aspectos. Es decir, no es como el ordenamiento burbuja.

    • A principios de los 2000, mientras desarrollaba juegos, aprendí que el ordenamiento burbuja tampoco es un perdedor en todos los aspectos.
      Rinde bien cuando la lista ya está casi ordenada, y eso ocurre en renderizado 3D al ordenar objetos según su distancia a la cámara. Si mueves o giras un poco la cámara, el ordenamiento burbuja funciona muy bien al volver a ordenar tomando como base el orden del fotograma anterior.
      Para evitar el peor caso, basta con contar la cantidad de comparaciones fallidas en la última pasada y el número de pasadas realizadas hasta el momento; si se supera un umbral, se cambia a otro algoritmo de ordenamiento.
    • El ordenamiento burbuja es excelente en hardware o con conjuntos casi ordenados.
    • El artículo dice literalmente que el diseño MVCC de pg es de los 90 y que ya nadie lo hace así.
      Es una tecnología de más de 30 años; aunque no sea un perdedor en todos los aspectos, creo que sí lo es en los más importantes.
  • Creo que este artículo se equivoca especialmente en la siguiente parte:
    “En los 2000, la sabiduría convencional eligió MySQL porque estrellas tecnológicas emergentes como Google y Facebook lo usaban. En los 2010, fue MongoDB, que se volvió ‘webscale’ gracias a escrituras no durables. Durante los últimos cinco años, PostgreSQL se convirtió en el DBMS favorito de internet. ¡Y con razón! Es confiable, rico en funcionalidades, extensible y encaja bien con la mayoría de las cargas de trabajo operativas.”
    Los ingenieros inteligentes eligieron Postgres no por una falacia de apelación a la popularidad, sino por la seguridad de los datos, ACID, su similitud con Oracle, MVCC, el cumplimiento del estándar SQL, el equipo de Postgres, una comunidad excelente y servicial, los tipos de datos, el alto rendimiento y la flexibilidad de BSD.
    Esas fueron también las razones por las que en ATT elegimos Postgres a principios de los 2000, y los DBA de Oracle aceptaron la transición con mucha facilidad. Mientras MySQL pasaba por una transición difícil, PG siguió fortaleciéndose y mejorando. Creo que Bruce Momjian tuvo un papel importante en este éxito, y la comunidad es realmente extraordinaria.

    • De forma similar, en 2005 mi preferencia cambió de MySQL a PostgreSQL.
      Fue porque quería usar vistas de base de datos para crear una capa de compatibilidad “en vivo” entre un esquema de base de datos AS400 antiguo y una app moderna en Rails.
      Después de eso, mi preferencia siguió creciendo gracias a la seguridad de los datos, DDL dentro de transacciones y cosas por el estilo.
  • “MySQL y Oracle almacenan deltas comprimidos entre la versión nueva y la versión actual (piénsalo como un git diff).”
    ¿No es famoso Git justamente por no almacenar diffs, sino objetos nuevos y objetos anteriores completos, como el método que usa Postgres aquí?

    • La oración citada no dice que Git almacene diffs, sino que lo que almacenan MySQL y Oracle es similar a un git diff.
    • Correcto. Cada versión de un archivo es un blob separado.
      Aunque usa packing para comprimir y acelerar los clones, la forma cruda con la que trabaja Git son esos blobs.
    • La comparación no era con el método de almacenamiento de Git, sino una analogía de que el método de almacenamiento de MySQL y Oracle es parecido al formato de git diff.
      Los repositorios Git también comprimen, y esa compresión es en cierto modo basada en diffs, pero no en el historial de commits como uno esperaría ingenuamente.
    • Se señaló que otros dijeron “git diffs”, pero Git en realidad usa deltas como optimización de bajo nivel en los pack files, y eso es parecido a la comparación con MySQL.
      En una consulta SQL tampoco se devuelve el diff tal cual.
    • Git diff se genera al vuelo, pero un diff sigue siendo un diff.
  • “La necesidad de que PostgreSQL modifique todos los índices de una tabla en cada actualización tiene varias implicaciones de rendimiento. Naturalmente, las consultas update se vuelven más lentas porque el sistema tiene que hacer más trabajo.”
    Me daba curiosidad esta amplificación de escritura. Es cierto que MySQL no necesita actualizar los índices de esa manera, pero la replicación de MySQL depende del binlog, y todos los cambios deben registrarse adicionalmente además de en la propia base de datos (redo log de InnoDB, etc.).
    Así que MySQL usado en un clúster parece tener otro tipo de amplificación de escritura. PostgreSQL reutiliza el WAL para la replicación, así que no tiene esa amplificación.
    Además, del lado receptor, MySQL primero escribe el binlog entrante en el relay log, y luego el hilo applier consume ese relay log, generando escrituras InnoDB adicionales y, con la configuración predeterminada, un binlog adicional.

  • Este tema no se puede discutir sin hablar del disco.
    Un SSD escribe páginas de 4 KB a la vez. Es decir, aunque solo actualices 1 bit, el disco lee 4 KB, cambia el bit y luego vuelve a escribir la página de 4 KB en una ranura nueva. Por lo tanto, la penalización de la copia depende del tipo de disco.

    • Interesante. Me pregunto cómo se refleja esto en la facturación de AWS.
      AWS cobra una tarifa fija por los MBps de IO, pero no sé si tiene una regla de redondeo hacia arriba al múltiplo de 4 KB más cercano, o si cobra la cantidad real de IO en la implementación de almacenamiento rastreando el volumen de escritura del propio drive, no la cantidad de solicitudes.
    • Las páginas de Postgres son de 8 KB, así que ese punto no tiene mucha relevancia.
  • “Oracle y MySQL no tienen este problema en su implementación de MVCC, porque los índices secundarios no almacenan la dirección física de la nueva versión. En su lugar, almacenan un identificador lógico (por ejemplo, ID de tupla, clave primaria), y el DBMS lo usa para encontrar la dirección física de la versión actual. Esto puede hacer más lentas las lecturas de índices secundarios, pero estos DBMS tienen otras ventajas en su implementación de MVCC que reducen el overhead”.
    Hay un comportamiento interesante que observé en MySQL. Era una base de datos de unos 500 GB y el esquema se parecía más a uno orientado a documentos que a uno relacional; SELECT id WHERE something; UPDATE what WHERE id=id era varios órdenes de magnitud más rápido que UPDATE what WHERE something.
    Sospecho que la razón de este comportamiento probablemente esté aquí. Eso sí, las cargas de trabajo normales no hacen esto; solo se vuelve lento en DML temporales para corregir inconsistencias.

    • SELECT es una operación de solo lectura, así que puede ejecutarse en paralelo.
      En cambio, UPDATE realmente escribe y también podría bloquear la tabla. UPDATE id=id permite bloqueo a nivel de fila. Aunque también existe el riesgo de perder registros insertados entre el SELECT y el UPDATE.
    • Opero algunas instancias de Postgres de más de 2 TB, mayormente de lectura, y también se parecen más a modelos orientados a documentos.
      Estoy de acuerdo en que las actualizaciones masivas pueden ser demasiado lentas. Al final, muchas veces terminas procesando las actualizaciones gradualmente por lotes, o incluso usando COPY.
  • “En la década de 2010 era MongoDB. Se volvió ‘webscale’ gracias a escrituras no durables”.
    Esto se sale del tema, pero de principio a fin fue marketing: https://news.ycombinator.com/item?id=15124306

    • MongoDB fue diseñado por exingenieros de DoubleClick como una base de datos DIY hecha de paso, porque no había ninguna DB que cumpliera con los requisitos que necesitaban para otro servicio.
      La versión 4.2.8 (2020) se volvió bastante sólida y, según se sabe, no tiene escrituras sucias: https://en.wikipedia.org/wiki/MongoDB#Technical_criticisms
  • Lo que más detesto es que incluso en 2024 todavía haya que poner un pooler de conexiones delante (por ejemplo, pgbouncer) para que sea usable.

  • OrioleDB intentó resolver este problema con un nuevo motor de almacenamiento: https://github.com/orioledb/orioledb

    • Está en el equipo de Supabase.
      Oriole ahora se unió a Supabase, y Alexander y su equipo están trabajando en ello a tiempo completo. El patch set está aquí: https://www.orioledb.com/docs#patch-set
      Se espera que también esté disponible para probar en la plataforma de Supabase hacia fines de este año.