Как работают курсоры в DB-API Python? - PullRequest
28 голосов
/ 18 января 2009

Я использую 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() 

или

rows = cursor.fetchmany()

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

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

Thx

Ответы [ 3 ]

7 голосов
/ 09 июня 2009

да, я знаю, что месяцы: P

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

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

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

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

2 голосов
/ 18 января 2009

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

1 голос
/ 18 января 2009

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

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

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

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