2014-02-13 2 views
1

Я выполнял итерацию по запросу в SQLAlchemy и выполнял обновления в строках, и я испытывал неожиданно низкую производительность, на несколько порядков медленнее, чем я ожидал. База данных содержит около 12 тыс. Строк. Мой первоначальный запрос и цикл выглядит следующим образом:Понимание производительности SQLAlchemy при итерации по истекшему запросу и обновлению

query_all = session.query(MasterImages).all() 

for record_counter, record in enumerate(query_all): 
    # Some stuff happens here, set_id and set_index are defined 
    session.query(MasterImages).\ 
      filter(MasterImages.id == record.id).\ 
      update({'set_id':set_id, 'set_index':set_index}) 
    if record_counter % 100 == 0: 
     session.commit() 
     print 'Updated {:,} records'.format(record_counter) 
session.commit() 

Первая итерация цикла была очень быстро, но тогда это казалось бы, остановится после первой фиксации. Я попробовал кучу разных подходов, но ничего не получал. Затем я попытался изменить мой запрос так только выбранные поля I, необходимые для расчета значения по set_id и set_index я использую в своем обновлении, как это:

query_all = session.query(MasterImages.id, MasterImages.project_id, 
          MasterImages.visit, MasterImages.orbit, 
          MasterImages.drz_mode, MasterImages.cr_mode).all() 

Это произвело исполнение я ожидал, пахоты через все записи в течение минуты. Подумав об этом некоторое время, я думаю, что моя проблема заключалась в том, что в моем первом запросе после коммита он превратился в устаревший запрос, потому что я обновил поле, которое было (необязательно) в запросе, который я повторял. Это, я думаю, вынудило Алхиму регенерировать запрос после каждой фиксации. Удалив поля, которые я обновлял из запроса, который я выполнял, я думаю, что смог использовать один и тот же запрос, и это привело к увеличению моей производительности.

Правильно ли я?

ответ

0

Отключить expire_on_commit.

С помощью expire_on_commit on SQLAlchemy отмечает все объекты в query_all как истекшие (или «устаревшие», как вы выразились) после .commit(). То, что истекает, означает, что при следующем попытке доступа к атрибуту вашего объекта SQLAlchemy выдает SELECT для обновления объекта. Отключение expire_on_commit не позволит этому сделать это. expire_on_commit - это опция, так что наивное использование ORM не нарушается, поэтому, если вы знаете, что делаете, вы можете спокойно отключить его.

Ваше исправление работает, потому что при указании столбцов (MasterImages.id и т. Д.) Вместо сопоставленного класса (MasterImages) в вашем запросе() SQLAlchemy возвращает вам простой кортеж python вместо экземпляра сопоставленного класса. Кортеж не предлагает функции ORM, т. Е. Не истекает, и он никогда не будет повторно извлекаться из базы данных.

+0

Так что 'expire_on_commit' является дополнительной оптимизацией, которую я мог бы сделать? Какова наилучшая практика того, когда и когда не использовать это? Кроме того, могу ли я исправить свое понимание старых запросов в моем исходном сообщении? – ACV

+0

Вид. SQLAlchemy отмечает все объекты в 'query_all' как истекшие (или« устаревшие », как вы выразились) после' .commit() ', а не после' .update() '. То, что истекает, означает, что при следующем попытке доступа к атрибуту на вашем объекте SQLAlchemy выдает 'SELECT' для обновления объекта. Отключение 'expire_on_commit' не позволит этому сделать это. 'expire_on_commit' - это опция, так что наивное использование ORM не нарушается, поэтому, если вы знаете, что делаете, вы можете спокойно отключить его. – univerio

+0

Я обновил вопрос, чтобы использовать соответствующий термин «expired» вместо «stale». Но вы можете объяснить, почему мой код ускорился, когда я изменяю запрос, который я повторял? – ACV

Смежные вопросы