2013-11-11 4 views
7

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

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

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

Это странно. Почему у вас есть класс myTable, и где ваши модели? –

+0

Извините, меня отняли, так как я не хотел загромождать его большим количеством кода, так как основной проблемой является транзакция. Класс myTable представляет собой просто представление таблицы в базе данных и вызывает класс tableRow, который расширяет sqlalchemy.ext.declarative.declarative_base. Что вы подразумеваете под моделями? – Lezan

ответ

12

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

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

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

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

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

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

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

Это, скорее всего, будет немного быстрее, но также менее удобным. Он работает так же, как и предыдущий сеанс, только строит инструкцию из Core, а не ORM.

+0

Спасибо, что я читал на сессиях и читал уроки этим утром, но я немного смущен первым выбором, когда вы инициализируете сеанс (вызывая session = Session()), у вас уже нет session.begin()? Разве вы не вызывали бы session.begin() дважды с помощью этого метода? – Lezan

+0

Игнорируйте этот последний комментарий, теперь я понимаю, что это связано с установкой автосообщения в сеансе на «Истина», чтобы начать транзакцию явно. И да, называя это от ядра быстрее, но оба работают действительно аккуратно, спасибо! – Lezan