「PythonのMySQLのInsertが遅い」
大量のデータを挿入したい場合、Insertに時間がかかる。
しかし一括でInsertすることで時間短縮することができる。
今回はそのバルクInsertについて紹介する。
一括でInsertする方法
pymysql
の execute
の代わりに 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が遅いと思ったら、 pymysql
の executemany
を試してみよう。