54138

[code]

    import sqlalchemy
    
    engine = sqlalchemy.create_engine('mysql+pymysql://user:pass@host/db')
    results = engine.execute('select * from large_table')
    
    for result in results:
        process_result(result)
    
[/code]

SQLAlchemy にて、上記のような、大きなテーブルから select してきて、その結果を何かしらの逐次処理にかけることがやりたくなりました。

`execute` の結果帰ってくるオブジェクトは `ResultProxy` ですが、これは、自分の理解だと DB
のカーソルをラップしたようなものだと認識しており、なので、上記のコマンドはいい感じに iterator を通じて、必要な分だけ `large_table`
からデータをフェッチし、それに対して `process_result` を実行してくれると思っていました。

しかし、上記のコマンドを実行したところ、これは大量のメモリを使用することがわかりました。具体的には、 `engine.execute` の段階で、
`select` 文の結果を、 results の中に全て fetch しているような動作をしているようです。

### 質問

  * SQLAlchemy にて、クエリの `execute` に対して、その結果をカーソル的に逐次処理したい場合、これはどのように実現できますか？


CC BY-SA 4.0
2019-04-11T01:59:31.467
54079
2019-04-13T09:29:40.497
754
question
python sqlalchemy
SQLAlchemy にて、クエリの execute の結果に対して、逐次処理を行いたい


[`stream_results`フラグ](https://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Connection.execution_options.params.stream_results)
を connection ないし statement
に対して指定することで、結果を一度にすべてバッファリングするのではなく、「ストリーム処理」を行うことが可能です。

これは、 psycopg2, mysqldb, ないし pymysql のアダプタのみで今現在は利用可能だそうです。

[code]

    import sqlalchemy
    
    engine = sqlalchemy.create_engine('mysql+pymysql://user:pass@host/db')
    connection = engine.connect()
    results = connection.execution_options(stream_results=True).execute(
      'select * from large_table'
    )
    
    for result in results:
        process_result(result)
    
[/code]

上記処理にて、メモリの増大が見られなくなったので、正しく動いている模様です。


CC BY-SA 4.0
2019-04-13T09:29:40.497
54138
2019-04-13T09:29:40.497
754
54079
answer