Python
sqlalchemy

SqlAlchemyのyield_perの挙動について

More than 1 year has passed since last update.


SqlAlchemyのyield_perというメソッド

Railsで言う、find_in_batchesですかね。大量データをselectする時に結果を全部メモリに格納することなく逐次処理してくれる素敵メソッドですね。

てっきりlimitとかoffsetとかをよしなにハンドリングしてくれるメソッドかと思ったら、そんなことなくて、selectした結果をストリームとして処理するメソッドなのですね。

SQLのログを見て、思い(込んだ)通りにSQLが出てこないことに悩む人が、きっと僕以外にもいるだろうと思ったのでメモしておきますね。

念のため使い方メモ


yield_per.sample.py

sess = Session(engine)

for obj in sess.query(Customer).filter_by(ownd_uid = n).yield_per(10):
hogehoge(obj)

このように書いておくとfilterの条件で選択したレコードが大量にあっても10件ずつselectしながら処理をしてくれるので、selectの結果を全部メモリに載せることなく逐次処理してくれます。

最高ですね。


おや?N本の接続を使っている?

MySQLの方でshow processlistしてみると、yield_perで呼び出しているコネクションはそれぞれ一本のコネクションを貼っているようですね。言われてみればそうか。

screen 2016-11-06 12.16.41.png

一番最初の945秒かかってるのが最上位のループなんですが、はてconnect_timeoutで切れないのだろうか...。(切れそうな気がする)

こういうの大量データを使ってないと見えないところだったりしますので、エラーが出たら、使い方について継続的にメモしていきますね。


結果:接続エラーは出ませんでした。

1〜2時間かかる処理でしたが、問題なく終わりました。

もしかして、長時間の接続をキープしてるとshow processlistにクエリ出なくなったりします?!

是非、MySQL側でどのような処理になっているのか、挙動を調べてみてください!