Извлечение больших двоичных объектов из PostgreSQL с помощью Python — «пауза» в начале

#python #postgresql #blob #psycopg2

#python #postgresql #большой двоичный объект #psycopg2

Вопрос:

Я хочу извлекать большие двоичные объекты из строк внутри отдельных файлов — и использую код Python, который выглядит следующим образом:

 connDB = psycopg2.connect(
    database=strDbName, user=strUser, password=strPass,
    host=strHost, port=strPort)
cur = connDB.cursor()
cmd = """
select id || '.pdf' as filename, blobColumn as binaryData
from someTable
"""
cur.execute(cmd)
while True:
    row = cur.fetchone()
    if row is None: break
    print "Generating:", row[0]
    open(row[0], 'w').write(row[1][:])
  

Это работает нормально, но когда таблица содержит более, например, 500 строк, я начинаю замечать задержку при запуске скрипта — как будто база данных «делает снимок» заранее, а затем «подает» мне этот снимок. Конечным результатом является то, что в течение некоторого времени нет вывода, а затем большие двоичные объекты начинают выливаться.

Если моя догадка верна:

  • Я бы очень хотел избежать этой «картинки» — потому что большие двоичные объекты большие, как и «картинка», напрягая БД и задерживая мой вывод без причины.
  • Альтернатива, которую я рассматриваю, — это чтение всех идентификаторов строк заранее, добавление их в массив Python, а затем цикл по этому массиву, выполняя по одному select blobColumn where id=... на итерацию. Разве это не должно быть лучше?

Спасибо за любые подсказки — и хотя речь идет о Python, PostgreSQL и psycopg2, мне было бы интересно услышать, зависит ли это от движка DB, не упускаю ли я лучшего использования API psycopg2 и т. Д.

Ответ №1:

Попробуйте использовать named cursor . По умолчанию psycopg2 используется значение 2000, но поскольку вы заметили пороговое значение около 500, попробуйте установить его намного ниже, скажем, 100 или 200. Вы делаете это просто, предоставляя параметр name конструктору cursor.

Это named cursor позволит psycopg2 автоматически запрашивать пакеты, настроив cursor для вас серверную часть. С Python другой стороны, вы просто выполняете итерацию как обычно, и при необходимости она будет получать больше данных с сервера.

Кроме того, может быть полезно взглянуть query plan на таблицы большего размера, чтобы увидеть, чем они отличаются от таблиц меньшего размера.

Если вы используете named cursor , после запуска execute , вы просто iterate вместо вызова fetchone или аналогичного.

т.е.

 for row in cur:
    # do stuff here
  

Комментарии:

1. Отличное предложение, сработало как шарм. Все, что мне нужно было сделать, это переключиться на «cur = connDB.cursor (name =’test’)», а затем «cur.itersize = 10» — после этого большие двоичные объекты начали появляться мгновенно. Спасибо!