【Django】レコードの一括作成・更新で処理を爆速に

bulk-create-update-title CODE

Djangoでレコードの一括作成・更新を行う方法を紹介します。

基本的にDBに対するクエリが多くなると処理に時間がかかるので、できるだけ発行するクエリを減らすことが良いコードに繋がります。

Djangoで同じモデルに対して作成や更新を複数回行う場合に、1クエリで処理できる bulk_create  bulk_update があります。

関数の使い方と、使わない場合との処理時間の違いをまとめました。

 

なお、この記事で使うPython・Djangoのバージョンは以下のとおりです。

Python 3.7
Django 2.2.5

bulk_create

 bulk_create はレコードを一括作成する関数です。

Django1系でもサポートされています。

bulk_createを使用しない場合

比較のために、ループ内でクエリを発行する場合の処理時間を計測しました。

例は、titleとpriceカラムを持つBookテーブルのレコードを1万件作成しています。

for i in range(10000):
    Book.objects.create(title='タイトル'+str(i), price=i)  #作成のクエリ発行

>> 65.8s

1万件作成するのに65.8秒かかりました。

 

bulk_createを使用した場合

同じレコード1万件を bulk_create を使用して作成すると、

add_books = []  # 作成クエリの配列
for i in range(10000):
    book = Book(title='タイトル'+str(i), price=i)
    add_books.append(book)  # 作成クエリを配列に格納

Book.objects.bulk_create(add_books)  # ここで追加のクエリ1つ発行

>> 2.4s

2.4秒で終わりました。(笑)

bulkを使う方が圧倒的に処理が速いです。

createやsaveと同様に作成するモデルインスタンスを作り、配列に格納して bulk_create でまとめて処理します。

 

bulk_update

 bulk_update はレコードを一括更新する関数です。

Django2.2からサポートされているのでご注意を!

bulk_updateを使用しない場合

比較のためにループ内でクエリを発行した場合を計測します。

例は、先ほど作成したBookレコードのpriceを全て100にするというものです。

books = Book.objects.all()  # レコード1万件取得
for book in books:
    book.price = 100
    book.save()  # 更新のクエリ発行

>> 90.6s

1万件更新するのに90.6秒かかりました。

 

bulk_updateを使用した場合

同じ更新を bulk_update を使用して行うと、

upd_books = []  # 更新クエリの配列
books = Book.objects.all()  # レコード1万件取得
for book in books:
    book.price = 100
    upd_books.append(book)  # 更新クエリを配列に格納
Book.objects.bulk_update(upd_books, fields=['price'])  # ここで更新クエリ1つ発行

>> 3.8s

3.8秒で終わりました。

更新の場合も圧倒的に早いですね。

 bulk_create と違いfieldsの配列に更新するカラムを指定する必要があります。

 

 bulk_create  bulk_update 両方に引数 batch_size を指定でき、指定した数ごとにクエリを発行させることができます。

膨大な数の作成・更新の場合は、 batch_size を5000や10000にしておく方がパフォーマンス的に良いでしょう。