Python postgres Я могу получить() 1 миллион строк?

Я использую модуль psycopg2 в python для чтения из базы данных postgres, мне нужно выполнить некоторую операцию для всех строк в столбце, который содержит более 1 миллиона строк.

Я хотел бы знать, может ли cur.fetchall() выйти из строя или заставить мой сервер опуститься? (поскольку моя оперативная память может быть не такой большой, чтобы хранить все эти данные)

q="SELECT names from myTable;"
cur.execute(q)
rows=cur.fetchall()
for row in rows:
    doSomething(row)

Каков умный способ сделать это?

Ответ 1

fetchall() выбирает до arraysize, поэтому, чтобы предотвратить массивное попадание в вашу базу данных, вы можете либо получать строки в управляемые партии, либо просто шаг через курсор до исчерпания:

row = cur.fetchone()
while row:
   # do something with row
   row = cur.fetchone()

Ответ 2

Рассмотрите возможность использования курсора на стороне сервера:

Когда выполняется запрос базы данных, курсор Psycopg обычно выбирает все записи, возвращенные бэкэнд, передавая их на клиентский процесс. Если запрос возвратил огромное количество данных, пропорционально большой объем памяти будет выделен клиентом.

Если набор данных слишком велик, чтобы его можно было практически обрабатывать на клиенте стороне, можно создать курсор на стороне сервера. Используя этот вид курсора можно передать клиенту только контролируемый количество данных, так что большой набор данных можно исследовать без сохраняя его полностью в памяти.

Вот пример:

cursor.execute("DECLARE super_cursor BINARY CURSOR FOR SELECT names FROM myTable")
while True:
    cursor.execute("FETCH 1000 FROM super_cursor")
    rows = cursor.fetchall()

    if not rows:
        break

    for row in rows:
        doSomething(row)

Ответ 3

Решение Burhan указывает на сокращение использования памяти для больших наборов данных за счет получения только одной строки:

row = cursor.fetchone()

Тем не менее, я заметил значительное замедление в наборе строк один за другим. Я обращаюсь к внешней базе данных через подключение к Интернету, что может быть причиной для этого.

Наличие на стороне сервера курсора и выборку рядов строк оказались наиболее эффективным решением. Вы можете изменить операторы sql (как в ответах alecxe), но есть также чистый подход python, используя функцию, предоставленную psycopg2:

cursor = conn.cursor('name_of_the_new_server_side_cursor')
cursor.execute(""" SELECT * FROM table LIMIT 1000000 """)

while True:
    rows = cursor.fetchmany(5000)
    if not rows:
        break

    for row in rows:
        # do something with row
        pass

вы найдете больше ссылок на стороне сервера в psycopg2 wiki

Ответ 4

Вот код, который следует использовать для простого курсора на стороне сервера со скоростью управления fetchmany.

Принцип состоит в том, чтобы использовать именованный курсор в Psycopg2 и дать ему хороший itersize для загрузки многих строк сразу, как это сделал бы fetchmany, но с одним циклом for rec in cursor, который делает неявным fetchnone().

С помощью этого кода я делаю запросы из 150 миллионов строк из таблицы с несколькими миллиардами строк в течение 1 часа и 200 мегабайт.

Ответ 5

Не уверены, что именованный курсор подходит без необходимости интерактивной прокрутки вперед/назад? Я могу ошибаться здесь.

Петля fetchmany утомительна, но я думаю, что это лучшее решение здесь. Чтобы облегчить жизнь, вы можете использовать следующее:

from functools import partial
from itertools import chain

# from_iterable added >= python 2.7
from_iterable = chain.from_iterable

# util function
def run_and_iterate(curs, sql, parms=None, chunksize=1000):
    if parms is None:
        curs.execute(sql)
    else:
        curs.execute(sql, parms)
    chunks_until_empty = iter(partial(fetchmany, chunksize), [])
    return from_iterable(chunks_until_empty)

# example scenario
for row in run_and_iterate(cur, 'select * from waffles_table where num_waffles > %s', (10,)):
    print 'lots of waffles: %s' % (row,)