Как работают курсоры в Python DB-API?
Я использую python с RDBMS (MySQL и PostgreSQL), и я заметил, что я действительно не понимаю, как использовать курсор.
Обычно, его script подключается к БД через клиентский DB-API (например, psycopg2 или MySQLdb):
connection = psycopg2.connect(host='otherhost', etc)
И затем создается курсор:
cursor = connection.cursor()
И тогда можно задать запросы и команды:
cursor.execute("SELECT * FROM etc")
Теперь, где результат запроса, интересно? это на сервере? или немного на моем клиенте и немного на моем сервере? И тогда, если нам нужно получить некоторые результаты, мы получаем их:
rows = cursor.fetchone()
или
rows = cursor.fetchmany()
Теперь скажем, я не извлекаю все строки и не решаю выполнить другой запрос, что произойдет с предыдущими результатами? Их накладные расходы.
Кроме того, должен ли я создавать курсор для каждой формы команды и постоянно использовать его для тех же самых команд; Я думаю, что psycopg2 может каким-то образом оптимизировать команды, которые выполняются много раз, но с разными значениями, как и стоит ли это?
спасибо
Ответы
Ответ 1
ya, я знаю это месяцы: P
Курсор DB-API, по-видимому, тщательно моделируется после курсоров SQL. Управление ресурсами (AFA) AFA, DB-API не указывает, должен ли клиент извлекать все строки или DECLARE для реального курсора SQL. Пока интерфейсы fetchXXX выполняют то, что они предполагают, DB-API счастлив.
Будут рассмотрены курсоры AFA psycopg2 (как вы, возможно, знаете), "неназванные курсоры DB-API" будут извлекать весь набор результатов - AFAIK, буферизованный в памяти libpq. "названные курсоры DB-API" (концепция psycopg2, которая может быть не переносимой), запросит строки по запросу (методы fetchXXX).
Как указано в "unbeknown", executemany можно использовать для оптимизации нескольких запусков одной и той же команды. Однако он не учитывает потребности в подготовленных заявлениях; когда повторные выполнения инструкции с разными наборами параметров не являются непосредственно последовательными, функция executeemany() будет выполнять так же, как и execute(). DB-API "предоставляет" авторам драйверов возможность кэшировать исполняемые операторы, но его реализация (то, что область/время жизни оператора?) Составляет undefined, поэтому невозможно установить ожидания в реализации DB-API.
Если вы загружаете много данных в PostgreSQL, я настоятельно рекомендую попробовать найти способ использования COPY.
Ответ 2
Предполагая, что вы используете PostgreSQL, курсоры, вероятно, только что реализованы с использованием API-интерфейса курсора базы данных. Вы можете посмотреть исходный код pg8000, чистый модуль DB-API Python PostgreSQL, чтобы увидеть, как он обрабатывает курсоры. Вы также можете посмотреть документацию PostgreSQL для курсоров.
Ответ 3
Если вы посмотрите здесь на mysqldb documentation, вы увидите, что они реализовали разные стратегии для курсоров. Итак, общий ответ: это зависит.
Изменить: Вот mysqldb API-документация. Существует некоторая информация о том, как ведет себя каждый тип курсора. Стандартный курсор хранит результирующий набор в клиенте. Поэтому я предполагаю, что есть накладные расходы, если вы не извлекаете все строки результатов, потому что даже строки, которые вы не извлекаете, должны быть переданы клиенту (возможно, по сети). Я предполагаю, что он не отличается от postgresql.
Если вы хотите оптимизировать операторы SQL, которые вы вызываете повторно со многими значениями, вы должны посмотреть на cursor.executemany(). Он подготавливает инструкцию SQL, так что ее не нужно анализировать каждый раз, когда вы ее вызываете:
cur.executemany('INSERT INTO mytable (col1, col2) VALUES (%s, %s)',
[('val1', 1), ('val2', 2)])