Как курсоры работают в Python DB-API?

Я использовал python с RDBMS (MySQL и PostgreSQL) и заметил, что действительно не понимаю, как использовать курсор.

Обычно его скрипт подключается к БД через клиентский DB-API (например, psycopg2 или MySQLdb):

connection = psycopg2.connect(host='otherhost', etc)

И затем создается курсор:

cursor = connection.cursor()

И тогда можно выдавать запросы и команды:

cursor.execute("SELECT * FROM etc")

Интересно, а где результат запроса? это на сервере? или немного на моем клиенте и немного на моем сервере? И затем, если нам нужно получить доступ к некоторым результатам, мы получаем их:

rows = cursor.fetchone() 

or

rows = cursor.fetchmany()

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

Кроме того, должен ли я создавать курсор для каждой формы команды и каким-то образом постоянно повторно использовать его для тех же команд; Я головой psycopg2 может как-то оптимизировать команды, которые выполняются много раз, но с разными значениями, как и стоит ли это делать?

Спасибо


person Nicholas Leonard    schedule 17.01.2009    source источник
comment
Re: лучшие практики для курсоров из FAQ ( initd.org/psycopg/docs/faq.html ): Наше предложение состоит в том, чтобы почти всегда создавать новый курсор и удалять старые, как только данные больше не требуются (вызывать для них close()). курсор для целой группы INSERT или UPDATE.   -  person Matthew Cornell    schedule 13.06.2013


Ответы (3)


да, я знаю, что это несколько месяцев :P

Курсор DB-API очень похож на курсоры SQL. Что касается управления ресурсами (строками) AFA, DB-API не указывает, должен ли клиент извлекать все строки или DECLARE фактический курсор SQL. Пока интерфейсы fetchXXX делают то, что должны, DB-API доволен.

Что касается курсоров AFA psycopg2 (как вы, возможно, хорошо знаете), «безымянные курсоры DB-API» будут извлекать весь набор результатов — AFAIK, буферизованный в памяти libpq. «именованные курсоры DB-API» (концепция psycopg2, которая может быть непереносимой) будут запрашивать строки по запросу (методы fetchXXX).

Как цитирует «неизвестный», executemany можно использовать для оптимизации нескольких запусков одной и той же команды. Однако он не учитывает потребности в подготовленных операторах; когда повторные выполнения инструкции с разными наборами параметров не являются прямыми последовательными, executemany() будет работать так же хорошо, как execute(). DB-API действительно «предоставляет» авторам драйверов возможность кэшировать выполняемые операторы, но его реализация (какова область действия/срок действия оператора?) не определена, поэтому невозможно установить ожидания для разных реализаций DB-API.

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

person jwp    schedule 09.06.2009

Предполагая, что вы используете PostgreSQL, курсоры, вероятно, просто реализованы с использованием собственного API курсоров базы данных. Вы можете просмотреть исходный код pg8000, чистого модуля Python PostgreSQL DB-API, чтобы увидеть как он обрабатывает курсоры. Вы также можете ознакомиться с документацией PostgreSQL для курсоров. .

person kquinn    schedule 18.01.2009

Когда вы посмотрите здесь на документацию mysqldb, вы увидите, что они реализовали различные стратегии для курсоров. Итак, общий ответ таков: это зависит.

Изменить: вот документация по API mysqldb. Есть некоторая информация о том, как ведет себя каждый тип курсора. Стандартный курсор сохраняет набор результатов в клиенте. Поэтому я предполагаю, что если вы не извлекаете все строки результатов, возникают накладные расходы, потому что даже те строки, которые вы не извлекаете, должны быть переданы клиенту (возможно, по сети). Я предполагаю, что это не так уж отличается от postgresql.

Если вы хотите оптимизировать операторы SQL, которые вы многократно вызываете со многими значениями, вам следует обратить внимание на cursor.executemany(). Он подготавливает оператор SQL, поэтому его не нужно анализировать каждый раз, когда вы его вызываете:

cur.executemany('INSERT INTO mytable (col1, col2) VALUES (%s, %s)',
                [('val1', 1), ('val2', 2)])
person Community    schedule 18.01.2009