sqlite3 - python DBファイルで:memory:を初期化する

sqlite3.connect(':memory:') でインメモリのDBを使う場合に中身を初期化しておきたい場合があります。一つの方法としてSQLを実行する方法があります。

conn = sqlite3.connect(':memory:', isolation_level=None)
c = conn.cursor()
sqls = [
    'CREATE TABLE table1 (data1 INTEGER, data2 INTEGER);',
    'INSERT INTO "table1" VALUES(1, 2);',
    'INSERT INTO "table1" VALUES(3, 4);'
]
for sql in sqls:
    c.execute(sql)


この方法でも良いのですが、データの量が多いと時間がかかります。たとえばカラム数4千でレコード数3万の場合2分ほど。これらの全てのカラムにインデックスを張った場合2時間ほどかかりました。


これでは時間がかかりすぎます。そこでSQLを実行するのではなく、事前に作成しておいたDBファイルをそのまま読み込んで初期化する方法を紹介します。


まずapswモジュールが必要になるので、こちらから落としてインストールしておきます。
そして、DBファイルで初期化を行う手順は以下のようになります。

import sqlite3
import apsw

_conn = apsw.Connection(':memory:') #1
conn = sqlite3.connect(_conn) #2
src_conn = apsw.Connection('src.db') #3

with _conn.backup("main", src_conn, "main") as backup:
    while not backup.done:
        backup.step(100) #4
  1. :memory: で apsw のコネクションを作成
  2. apsw で sqlite3 のコネクションを作成
  3. 初期化用のDBファイルで apsw のコネクションを作成
  4. 初期化用BDから :memory: へデータをコピーしていく

backup.step(100) で指定している数値は一度にコピーするページサイズです。小さくすればwhileが多く回りますが、適当な数値を入れておけば何を指定して問題ないと思います。


この方法を使うと、SQL文を実行したときにかかってた2時間が、なんと10秒まで短縮されました。