DB Python

PythonでMySQLに一括バルクInsert

「PythonのMySQLのInsertが遅い」
大量のデータを挿入したい場合、Insertに時間がかかる。
しかし一括でInsertすることで時間短縮することができる。
今回はそのバルクInsertについて紹介する。


一括でInsertする方法

pymysqlexecute の代わりに executemany を使うと一括でInsertできる。

参考:
pymysqlでbulkインサート - MasterYodaの昼下がり


検証

準備

pipで pymysql のライブラリをインストールする。

pip install pymysql

MySQLのDBに検証用のテストテーブルを作る。

CREATE TABLE <code>hoge</code> (
  <code>id</code> int(11) NOT NULL AUTO_INCREMENT,
  <code>name</code> varchar(50) NOT NULL,
  <code>value</code> double NOT NULL,
  <code>text</code> text NOT NULL,
  PRIMARY KEY (<code>id</code>)
) ENGINE=InnoDB AUTO_INCREMENT=98289 DEFAULT CHARSET=latin1


個別Insert

ローカルのDBに100,000行Insertするのに約13秒。

import pymysql
import datetime

print("Connect to DB")
conn = pymysql.connect(user="root", password="", host="localhost", database="test")

# Insert one by one
def insert_data(values):
    insert_sql = "INSERT INTO test.hoge (name, value, text) values (%s,%s,%s)"

    cur = conn.cursor()
    for value in values:
        cur.execute(insert_sql, value)

def main():
    # Generate data
    values = []
    print("Generate data")
    for i in range(100000):
        name = "name_{}".format(i)
        value = i
        text = "text_{}".format(i)
        values.append([name,value,text])
    print("Length of data: {}".format(len(values)))
    print()

    # Insert one by one
    print("Insert data")
    start_time = datetime.datetime.now()
    print("Start:" + str(start_time))
    insert_data(values)
    end_time = datetime.datetime.now()
    print("End:" + str(end_time))
    diff_time = end_time - start_time
    print("Diff:" + str(diff_time))
    print()

if __name__ == "__main__":
    main()


一括Insert

違いは insert_data_bulk の中で executemany を使っている。
ローカルのDBに100,000行Insertするのに約2秒
5~6倍くらい早くなっている。
ちなみに1,000,000行で実行すると個別137秒、一括26秒なのでやはり5倍ほど早い。

import pymysql
import datetime

print("Connect to DB")
conn = pymysql.connect(user="root", password="", host="localhost", database="test")

# Bulk Insert
def insert_data_bulk(values):
    print("Insert bulk data")
    insert_sql = "INSERT INTO test.hoge (name, value, text) values (%s,%s,%s)"

    cur = conn.cursor()
    cur.executemany(insert_sql, values)

def main():
    # Generate data
    values = []
    print("Generate data")
    for i in range(100000):
        name = "name_{}".format(i)
        value = i
        text = "text_{}".format(i)
        values.append([name,value,text])
    print("Length of data: {}".format(len(values)))
    print()

    # Bulk Insert
    print("Insert data")
    start_time = datetime.datetime.now()
    print("Start:" + str(start_time))
    insert_data_bulk(values)
    end_time = datetime.datetime.now()
    print("End:" + str(end_time))
    diff_time = end_time - start_time
    print("Diff:" + str(diff_time))
    print()

if __name__ == "__main__":
    main()


まとめ

MySQLのInsertが遅いと思ったら、 pymysqlexecutemany を試してみよう。



関連商品

ITipsと同じようなブログを作る方法

ブログに興味がありますか?

もしブログに興味がある場合は↓このページ↓を参考にすれば、ITipsと同じ構成でブログを作ることができます

サーバー、ドメイン、ASPと【ブログに必要なものは全て】このページに書きました。
同じ構成でブログ作るのはいいけど、記事はマネしないでネ (TДT;)

ランキング参加中

にほんブログ村 IT技術ブログへ

他にもブログやSNSで紹介してくれると励みになります。

はてブのコメントで酷評されると泣きます(´;ω;`)

-DB, Python
-,

© 2022 ITips