2013-07-25 6 views

答えて

40

デフォルトのカーソル、MySQLdb.cursors.Cursorを使用している場合、結果セット全体がcursor.execute()が完了した時点で(すなわち、Pythonのリストに)クライアント側に保存されます。

したがって、あなたは

for row in cursor: 

を使用している場合でも、あなたは、メモリフットプリントの減少を得ることはありません。結果セット全体はすでにリストに格納されています(MySQLdb/cursors.pyのself._rowsを参照)。あなたが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を必要としないため、メモリの節約、サーバから1つずつフェッチされます。

他にも既に述べたように、cursor.fetchall()list(cursor)は本質的に同じです。

2

list(cursor)カーソルが反復可能であるために機能します。あなたはまた、ループ内でcursorを使用することができます。

for row in cursor: 
    # ... 

良いデータベースアダプタ実装は、それがに設定されフル結果を保持する必要がないので、必要なメモリフットプリントを節約、サーバーからのバッチで行をフェッチしますメモリ。 cursor.fetchall()にはがあり、代わりに完全なリストを返します。

list(cursor)を使用している点は、cursor.fetchall()以上です。エンドエフェクトはまったく同じですが、代わりに結果をストリーミングする機会が無駄になりました。

+0

* "cursor.fetchall()に比べてリスト(カーソル)を使用することはほとんどありませんが、最終的には同じ結果になりますが、代わりに結果をストリーミングする機会が無駄になります。 PythonデータベースAPI。 'cursor.fetchall()'が一貫性のない戻り値の型を持つMySQLdbやその後継者PyMySQLの特定のケースではあまり真実ではありません(常に 'list(cursor)'を使用すると、ほとんどのカーソル・サブクラスはループしてもストリーミングを行わず、代わりにすべての結果をメモリーに読み込んでから最初の結果を生成します。 –

+0

@ MarkAmery:私は「良いデータベースアダプタの実装」という言葉を慎重に使用しています。私は、既存のMySQLの実装は、私が投稿を書いたときにすべての結果をプリフェッチしていると思っていました。 –

9

cursor.fetchall()およびlist(cursor)は本質的に同じである。別のオプションは、リストを取得し、代わりに裸のカーソルオブジェクトの上だけでループしないことです。

for result in cursor: 

それが全体の結果をフェッチする必要がないように、結果セットが大きい場合、これは、より効率的にすることができそれをすべてメモリに保存しておきます。それぞれのアイテムを段階的に取得することができます(またはバッチでバッチをバッチ処理することもできます)。

+1

これは、ほとんどの[PEP 249](https://www.python.org/dev/peps/pep-0249)の実装には当てはまりますが、MySQLdbやPyMySQLではそうではありません。 'list(cursor) cursor.fetchall() '(後者はリストまたはタプルのいずれかを一貫して返さないため、前者は常に一貫してリストを返すので)、ほとんどのカーソル実装は反復処理を開始するとすぐにメモリ全体に結果セットを取得します。 –

3

A(のMySQLdb/PyMySQL固有の)注目に値する違いDictCursorを使用すると、結果セットが、それはあなたを与える場合には、空でない限りcursor.fetchall()はあなたにリストを与えながらlist(cursor)は常に、あなたのリストを与えるということです空のタプル。これはMySQLdbのケースであり、より新しいバージョンのケースに残っていますPyMySQL、後方互換性の理由からwill not be fixedです。これはisn't a violation of Python Database API Specificationですが、まだ驚くべきことですが、シーケンスではなく、リストと誤って誤ってタイプエラーが発生する可能性があります。

上記を踏まえて、結果セットが空の奇妙なタイプのエラーによってキャッチされることを避けるため、常にlist(cursor)cursor.fetchall()よりも優先することをお勧めします。