※"データベース" とはPostgreSQL(またはAmazon RedShift)を指しています。
TLDR
pyscopg2のサーバーサイドカーソルを併用してデータを読み込んでいく必要がある。
(※PostgreSQL限定)
サーバーサイドカーソル、クライアントサイドカーソルについては下記記事が大変参考になる。
PythonとDB: DBIのcursorを理解する
事象
pandasでは、一度にメモリに乗り切らない巨大なデータを一定量ごとに読み込んで逐次処理するためのchunksize
オプションが用意されている。
しかし、巨大なDBテーブルの読み込みにchunksize
を指定してもメモリエラーが発生するケースがあった。
>>> import pandas as pd
>>> engine = get_engine()
# 10,000行テーブルの読込み(成功)
>>> small_df = pd.read_sql_table('small-table', con=engine)
>>> len(small_df)
10000
# chunksize を指定して10,000,000行のテーブル読込み(失敗)
>>> large_df = pd.read_sql_table('large-table', con=engine, chunksize=10000)
$ Killed # メモリエラーで強制終了
解決方法
psycopg2の名前付きカーソル(= サーバーサイドカーソル)を使用する。
import psycopg2
import pandas as pd
def get_psycopg2_connection():
...
con = get_psycopg2_connection()
# サーバーサイドカーソルの定義
cursor = con.cursor('large-table-cursor')
cursor.execute('SELECT * FROM "larget-table" ;')
while True:
rows = cursor.fetchmany(10000)
if len(rows) == 0:
break
# カラム一覧を取得
columns = [desc.name for desc in cursor.description]
# データフレームに格納
df = pd.DataFrame(rows, columns=columns)
con.close()
備考
read_sql_table
/read_sql_query
関数ではchunksize
を指定してもクライアントサイドカーソルが使われていると思われる(ソースコードレベルでの確証なし)。
Amazon RedShiftのドキュメントによると、巨大なテーブルに対してカーソルを使用することは推奨されていない。
※結果セットを一時的にリーダーノードに保持するため