SQLAlchemyのINSERTを高速化してみた

この記事は公開されてから半年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

PythonからMySQLにアクセスする際にSQLAlchemyを使用しているのですが、100万件ほどの大量データをINSERTする場合に処理時間が非常に長くかかってしまったため、高速化に取り組んでみました。

目次

実行環境

  • requirements.txt
  • DB
    下図のようなシンプルな構成です。
    employeeテーブルに100万件INSERTします。

  • Database

  • Model
  • 100万件データ
    CSVファイルに100万行のデータを用意してPythonでCSVを読み込みます。

困ったこと

下記のように1件ずつINSERTしようとすると30分経っても終わらず処理時間がかなり長くなります。
(逐次COMMITしているので当然といえば当然ですが…)

処理時間:30分以上(途中で中断しました)

高速化してみました

そこで、下記4通りの方法でそれぞれ処理時間を計測してみました。

複数件を一度にINSERTする方法

「add_all」を使用することで複数件を一度にINSERTすることができるようです。
これにより逐次COMMITがなくなり、結果も18分程度と処理時間の改善はされましたが、まだまだ改善の余地はありそうです。

処理時間:0:18:20.953209(約18分20秒)

一括INSERTする方法

「bulk_save_objects」を使用することで一括INSERTすることができるようです。
これにより処理時間が1分もかからず、かなりの高速化ができました!

処理時間:0:00:39.395299(約39秒)

Core機能を使用してINSERTする方法

一括INSERTでも十分早いのですが、SQLAlchemyのCore機能である「sqlalchemy.core」を使用することで処理の高速化を実現できます。
これまでと違い、データ型がdict型になります。

処理時間:0:00:24.264684(約24秒)

INSERTステートメントを使用する方法

SQLAlchemyのINSERTステートメントを使用することで高速化する方法があるようです。
ORM 一括 INSERT ステートメント
どうやらSQLAlchemy 2.0にてinsertステートメントを使用すると一括INSERTモードで処理してくれるようです。
実際に試してみます。

処理時間:0:00:27.155937(約27秒)

まとめ

これまで実施したINSERT方法と処理時間のまとめです。
30分以上かかっていた処理がかなり高速化されました。

INSERT方法 処理時間
複数件を一度にINSERTする方法 約18分20秒
一括INSERTする方法 約39秒
Core機能を使用してINSERTする方法 約24秒
INSERTステートメントを使用する方法 約27秒

ORM機能の維持にこだわらない場合は「Core機能」を使用して、維持したい場合は「INSERTステートメント」を使用すると良さそうです。

投稿者プロフィール

nagura
2021年4月からスカイアーチに中途入社しました。
AWSともっと仲良くなるべく日々勉強中です。