Más rápido no siempre es mejor: elegir la estrategia de inserción de PostgreSQL adecuada en Python (+puntos de referencia)

demuestra que es perfectamente posible insertar 2 millones de registros por segundo en Postgres. En lugar de perseguir micro-puntos de referencia, en este artículo daremos un paso atrás para hacer una pregunta más importante: ¿Qué abstracciones realmente se ajustan a nuestra carga de trabajo?

Veremos 5 formas de insertar datos en Postgres usando Python. El objetivo no es simplemente observar las velocidades de las plaquitas y coronar a un ganador, sino comprender las compensaciones entre abstracción, seguridad, conveniencia y rendimiento.

Al final entenderás:

las fortalezas y debilidades de ORM, Core y las inserciones a nivel de controlador cuando el rendimiento realmente importa cómo elegir la herramienta adecuada sin demasiada ingeniería

Por qué son importantes las inserciones rápidas

Las cargas de trabajo de inserción de gran volumen aparecen en todas partes:

cargar millones de registros sincronizar datos de API externas rellenar tablas de análisis ingerir eventos o registros en almacenes

Las pequeñas ineficiencias se agravan rápidamente. Convertir un trabajo de inserción de 3 minutos en uno de 10 segundos puede reducir la carga del sistema, liberar trabajadores y mejorar el rendimiento general.

Dicho esto, más rápido no significa automáticamente mejor. Cuando las cargas de trabajo son pequeñas, rara vez vale la pena sacrificar la claridad y la seguridad en aras de ganancias marginales.

Comprender cuándo el desempeño importa y por qué es el verdadero objetivo.

¿Con qué herramienta utilizamos para insertar?

Para hablar con nuestra base de datos Postgres necesitamos un controlador de base de datos. En nuestro caso, esto es psycopg3 con SQLAlchemy en capas encima. Aquí hay una distinción rápida:

Psycopg3 (el conductor)

psycopg3 es un controlador PostgreSQL de bajo nivel para Python. Esta es una abstracción muy delgada con una sobrecarga mínima que se comunica directamente con Postgres.
La compensación es la responsabilidad: usted mismo escribe SQL, administra el baño y maneja la corrección explícitamente.

SQLAlquimia

SQLAlchemy se encuentra encima de controladores de bases de datos como psycopg3 y proporciona dos capas:

1) Núcleo de SQLAlchemy
Esta es la capa de abstracción y ejecución de SQL. Es independiente de la base de datos, lo que significa que usted escribe expresiones de Python y Core las traducirá a SQL en el dialecto correcto de la base de datos (PostgreSQL/SQL Server/SQLite) y vincula los parámetros de forma segura.

2) ORM de SQLAlchemy
ORM se basa en Core y resume aún más. Asigna clases de Python a tablas, rastrea el estado de los objetos y maneja relaciones. El ORM es muy productivo y seguro, pero toda esa contabilidad genera gastos generales, especialmente para operaciones masivas.

En breve:
Los tres existen en un espectro. Por un lado está ORM, que le quita mucho trabajo y proporciona mucha seguridad a costa de gastos generales. Por otro lado, está el controlador, que es muy básico pero proporciona el máximo rendimiento. Core está justo en el medio y le brinda un buen equilibrio entre seguridad, rendimiento y control.

Dicho simplemente:

ORM le ayuda a utilizar el Core más fácilmente Core le ayuda a utilizar el controlador de forma más segura e independiente de la base de datos

El punto de referencia

Para mantener el punto de referencia justo:

Cada método recibe datos en la forma para la que fue diseñado.
(objetos ORM para ORM, diccionarios para Core, tuplas para Driver) solo se mide el tiempo dedicado a mover datos de Python a Postgres. ningún método es penalizado por el trabajo de conversión. La base de datos existe en el mismo entorno que nuestro script Python; esto evita que nuestro punto de referencia comience a verse obstaculizado por la velocidad de carga, por ejemplo

El objetivo no es “encontrar la inserción más rápida”, sino comprender qué hace bien cada método.

Tiempos de inserción por tamaño de lote para 5 métodos diferentes

1) ¿Más rápido siempre es mejor?

¿Qué es mejor? ¿Un Ferrari o un Jeep?

Esto depende del problema que estés intentando resolver.
Si estás atravesando un bosque, ve con el jeep. Si quieres ser el primero en cruzar la línea de meta, el Ferrari es una mejor alternativa.

Lo mismo se aplica al insertar. Reducir 300 milisegundos de una inserción de 10 segundos puede no justificar una complejidad y un riesgo adicionales. En otros casos, esa ganancia vale la pena.

En algunos casos, el método más rápido en papel es el más lento si se tiene en cuenta:

La corrección del coste de mantenimiento garantiza la carga cognitiva.

2) ¿Cuál es tu punto de partida?

La estrategia de inserción correcta se basa menos en el número de filas y más en el aspecto que tienen sus datos

El ORM, el Core y el controlador no son herramientas que compitan. Están optimizados para diferentes propósitos:

MétodoPropósitoORM (add_all)Lógica empresarial, corrección, lotes pequeñosORM(bulk_save_object)Objetos ORM a escalaNúcleo (ejecutar)Datos estructurados, abstracción ligera Controlador (ejecutar muchas)Filas sin procesar, alto rendimiento Controlador (COPIAR)Ingestión masiva, ETL, cargas de trabajo de manguera contra incendios

Un ORM sobresale en aplicaciones con mucho CRUD donde la claridad y la seguridad son lo más importante. Piense en sitios web y API. El rendimiento suele ser “suficientemente bueno” y la claridad es más importante.

Core brilla en situaciones en las que desea tener control sin escribir SQL sin formato. Piense en la ingesta de datos, trabajos por lotes, canales de análisis y servicios sensibles al rendimiento como trabajos ETL.
Usted sabe exactamente qué SQL desea, pero no desea administrar las conexiones o las diferencias de dialecto usted mismo.

El controlador está optimizado para un rendimiento máximo; escrituras extremadamente grandes, como escribir millones de filas para conjuntos de entrenamiento de ML, cargas masivas, mantenimiento o migraciones de bases de datos o servicios de ingesta de baja latencia.

El controlador minimiza la extracción y la sobrecarga de Python y le brinda el mayor rendimiento. La desventaja es que tienes que escribir SQL manualmente, lo que facilita cometer errores.

3) No hagas coincidir las abstracciones

El ORM no es lento. COPIAR no es mágico

Los problemas de rendimiento aparecen cuando forzamos los datos a través de una abstracción para la que no están diseñados:

Uso de Core con objetos ORM de SQLAlchemy – >lento debido a la sobrecarga de conversión Uso de ORM con tuplas – >volumen de ORM incómodo y frágil en el proceso ETL – >gastos generales desperdiciados

A veces, bajar a un nivel inferior puede reducir el rendimiento.

¿Cuándo elegir cuál?

Regla de oro:

CapaÚsalo cuando…ORMEstás creando una aplicación (corrección y productividad)NúcleoEstás moviendo o transformando datos (equilibrio entre seguridad y velocidad)ConductorEstás superando los límites de rendimiento (potencia bruta y responsabilidad total)

Conclusión

En los sistemas de datos e inteligencia artificial, el rendimiento rara vez está limitado por la base de datos. Está limitado por qué tan bien se alinea nuestro código con la forma de los datos y las abstracciones que elegimos.

Las API ORM, Core y Driver-level forman un espectro que va desde seguridad de alto nivel hasta potencia de bajo nivel. Todas son herramientas excelentes cuando se utilizan en el contexto para el que están diseñadas.

El verdadero desafío no es saber qué se ayuna, sino seleccionar la herramienta adecuada para su situación.

Espero que este artículo haya sido tan claro como pretendía, pero si este no es el caso, hágame saber qué puedo hacer para aclararlo más. Mientras tanto, consulte mis otros artículos sobre todo tipo de temas relacionados con la programación.

¡Feliz codificación!

—Mike

Pd: ¿te gusta lo que estoy haciendo? ¡Sígueme!