cursor.fetchall() против списка (курсор) в Python

Оба метода возвращают список возвращенных элементов запроса, я что-то здесь упустил?
Или они действительно имеют идентичные использования?
Есть ли различия в производительности?

4 ответа

Решение

Если вы используете курсор по умолчанию, MySQLdb.cursors.Cursorвесь набор результатов будет храниться на стороне клиента (т.е. в списке Python) к тому времени, когда cursor.execute() выполнен.

Поэтому, даже если вы используете

for row in cursor:

Вы не будете получать никакого сокращения памяти. Весь набор результатов уже был сохранен в списке (см. self._rows в MySQLdb/cursors.py).

Однако, если вы используете SSCursor или SSDictCursor:

import MySQLdb
import MySQLdb.cursors as cursors

conn = MySQLdb.connect(..., cursorclass=cursors.SSCursor)

затем набор результатов сохраняется на сервере mysqld. Теперь вы можете написать

cursor = conn.cursor()
cursor.execute('SELECT * FROM HUGETABLE')
for row in cursor:
    print(row)

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

В противном случае, как уже говорили другие, cursor.fetchall() а также list(cursor) по сути то же самое.

cursor.fetchall() а также list(cursor) по сути то же самое. Другой вариант - не извлекать список, а вместо этого просто зацикливаться на объекте курсора:

for result in cursor:

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

list(cursor) работает, потому что курсор является итеративным; Вы также можете использовать cursor в цикле:

for row in cursor:
    # ...

Хорошая реализация адаптера базы данных будет извлекать строки партиями с сервера, экономя при этом необходимый объем памяти, поскольку не нужно будет хранить полный набор результатов в памяти. cursor.fetchall() должен вернуть полный список.

Там нет особого смысла в использовании list(cursor) над cursor.fetchall(); конечный эффект тогда действительно тот же, но вместо этого вы упустили возможность передавать результаты.

Разницу (специфичную для MySQLdb/PyMySQL) стоит отметить при использовании DictCursor в том, что list(cursor) всегда даст вам список, а cursor.fetchall() выдает список, если результирующий набор не пуст, и в этом случае он дает пустой кортеж. Это имело место в MySQLdb и остается в более новой версии PyMySQL, где это не будет исправлено по причинам обратной совместимости. Хотя это не является нарушением спецификации API базы данных Python, это все же удивительно и может легко привести к ошибке типа, вызванной ошибочным предположением, что результатом является список, а не последовательность.

Учитывая вышесказанное, предлагаю всегда отдавать предпочтение list(cursor) над cursor.fetchall(), чтобы избежать попадания в загадочную ошибку типа в крайнем случае, когда ваш набор результатов пуст.

Вы можете использовать понимание списка, чтобы внести элемент из вашего кортежа в список:

conn = mysql.connector.connect()
cursor = conn.cursor()
sql = "SELECT column_name FROM db.table_name;"
cursor.execute(sql)

results = cursor.fetchall()
# bring the first item of the tuple in your results here
item_0_in_result = [_[0] for _ in results]

Другие вопросы по тегам