Транзакции и sqlalchemy

Я пытаюсь выяснить, как вставить много (в порядке 100k) записей в БД, используя sqlalchemy в python3. Все указывает на использование транзакций, однако я немного смущен тем, как это делается. На некоторых страницах указано, что вы получаете транзакцию от connection.begin (), другие места говорят, что это сессия.begin() и этой странице здесь говорит, что это сессии.create_transaction (), который не существует.

вот что я пытаюсь сделать:

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()

1 ответов


я настоятельно рекомендую вам сделать оба учебника, прежде чем продолжить свою поездку с SQLAlchemy. Они действительно полезны и объясняют многие концепции. После этого, я предлагаю вам прочитать используя заседании как это затем продолжается, чтобы объяснить, как сессия вписывается во все это.

к вашей проблеме, 2 решения: одно используя ОРМ и другое используя ядр. Первое легче, второе быстрее. Давай сначала выберем легкий путь. Сделка только используется, чтобы обернуть все ваши заявления в одну операцию. То есть, если что-то терпит неудачу, вы можете прервать все это и не остаться с чем-то где-то посередине. Таким образом, вы, скорее всего, хотите транзакцию, но она будет работать без нее. Вот самый быстрый способ:

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

в зависимости от ваших данных SQLAlchemy может даже быть в состоянии оптимизировать ваш INSERT заявление в Таким образом, что он выполняет несколько одновременно. Вот что происходит:

  • сделки с помощью session.begin
  • данные добавляются (используя add_all, но цикл с несколькими add также было бы хорошо)
  • сеанс зафиксирован. Если что-то пойдет не так, операция будет прервана и можно исправить ошибку.

таким образом, это явно хороший способ, но это не самый быстрый способ, потому что SQLAlchemy должен пройти через все алгоритмы ORM, которые могут произвести некоторые накладные расходы. Если это одноразовая база данных инициализация, вы можете избежать ORM. В этом случае вместо создания класса ORM (tableRow), создать словарь со всеми ключами (как зависит от данных). Опять же, вы можете использовать context manager:

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

это, вероятно, будет немного быстрее, но и менее удобно. Он работает так же, как и сеанс выше, только он строит оператор из ядра, а не ORM.