LoginSignup
0
0

More than 3 years have passed since last update.

【Pandas】データベーステーブル読込み時のメモリエラーを回避する

Posted at

※"データベース" とは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のドキュメントによると、巨大なテーブルに対してカーソルを使用することは推奨されていない。
※結果セットを一時的にリーダーノードに保持するため

参考: カーソルを使用するときのパフォーマンスに関する考慮事項

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0