Transacciones y sqlalchemy

Estoy tratando de averiguar cómo insertar muchos registros (en el orden de 100k) en un db usando sqlalchemy en python3. Todo apunta a usar transacciones, sin embargo, estoy un poco confundido en cuanto a cómo se hace eso. Algunas páginas indican que obtienes una transacción de connection.begin (), otras partes dicen que es session.begin () y esta página aquí dice que es session.create_transaction () que no existe.

Esto es lo que estoy tratando de hacer:

def addToTable(listOfRows): engine = create_engine('postgresql+pypostgresql:///%s' % db,echo = False) Session = sessionmaker(bind = engine) session = Session() table = myTable(engine,session) for row in listOfRows: table.add(row) table.flush() ### ideally there would be a counter and you flush after a couple of thousand records class myTable: def __init__(self,engine,session): self.engine = engine self.session = session self.transaction =createTransaction()# Create transaction code here def add(self,row): newRow = tableRow(row) ## This just creates a representation of a row in the DB self.transaction.add(newRow) self.transaction.flush() def flush(self): self.transaction.commit() 

Le sugiero que realice ambos tutoriales antes de continuar su viaje con SQLAlchemy. Son realmente útiles y explican muchos conceptos. Luego, le sugiero que lea Cómo usar la sesión, ya que esto continúa para explicar cómo la sesión se adapta a todo esto.

Para su problema, hay dos soluciones: una que usa el ORM y la otra que usa el Core. Lo primero es más fácil, lo segundo es más rápido. Tomemos el camino fácil primero. Una transacción solo se utiliza para envolver todas sus declaraciones en una sola operación. Es decir, si algo falla, puedes abortar todo y no te queda algo en algún lugar intermedio. Así que lo más probable es que quieras una transacción, pero funcionaría sin una. Aquí está la manera más rápida:

 with session.begin(): session.add_all([tableRow(row) for row in listOfRows]) 

Dependiendo de sus datos, SQLAlchemy podría incluso optimizar su statement INSERT de tal manera que se ejecute múltiples a la vez. Aquí está lo que está pasando:

  • Se inicia una transacción utilizando session.begin
  • Los datos se agregan (usando add_all , pero un bucle con varios add también estaría bien)
  • La sesión está comprometida. Si algo sale mal aquí, la transacción será abortada y puede corregir el error.

Así que esta es claramente una buena manera, pero no es la más rápida, porque SQLAlchemy tiene que pasar por todos los algoritmos de ORM que pueden producir algo de sobrecarga. Si se trata de una inicialización de base de datos única, puede evitar el ORM. En ese caso, en lugar de crear una clase ORM ( tableRow ), crea un diccionario con todas las claves (cómo depende de los datos). Nuevamente puedes usar un administrador de contexto:

 with engine.begin() as connection: connection.execute(tableRow.__table__.insert(). values([row_to_dict(row) for row in listOfRows])) 

Esto probablemente sería un poco más rápido pero también menos conveniente. Funciona de la misma manera que la sesión anterior solo que construye la statement desde el Core y no el ORM.