sqlite3データベースにロードしたい約30000行のデータのファイルがあります。データの各行に対して挿入ステートメントを生成するよりも速い方法はありますか?
データはスペースで区切られ、sqlite3テーブルに直接マップされます。ボリュームデータをデータベースに追加するための一括挿入方法はありますか?
それが組み込まれていない場合、誰かがこれを行うためのいくつかの明らかに素晴らしい方法を考案しましたか?
APIからそれを行うC++の方法はありますか?
.import
コマンドを使用したい。例えば:
$ cat demotab.txt
44 92
35 94
43 94
195 49
66 28
135 93
135 91
67 84
135 94
$ echo "create table mytable (col1 int, col2 int);" | sqlite3 foo.sqlite
$ echo ".import demotab.txt mytable" | sqlite3 foo.sqlite
$ sqlite3 foo.sqlite
-- Loading resources from /Users/ramanujan/.sqliterc
SQLite version 3.6.6.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from mytable;
col1 col2
44 92
35 94
43 94
195 49
66 28
135 93
135 91
67 84
135 94
この一括読み込みコマンドは SQL ではなく、SQLite のカスタム機能であることに注意してください。echo
インタラクティブなコマンド ライン インタープリターsqlite3
.
PostgreSQL では、次のようになりますCOPY FROM
:
http://www.postgresql.org/docs/8.1/static/sql-copy.html
MySQL ではLOAD DATA LOCAL INFILE
:
http://dev.mysql.com/doc/refman/5.1/en/load-data.html
最後に、 の値には注意して.separator
ください。これは、一括挿入を行うときによくある落とし穴です。
sqlite> .show .separator
echo: off
explain: off
headers: on
mode: list
nullvalue: ""
output: stdout
separator: "\t"
width:
実行する前に、区切り文字をスペース、タブ、またはコンマに明示的に設定する必要があります.import
。
また、いくつかのパラメーターを微調整して、速度を上げることもできます。具体的には、おそらく必要ですPRAGMA synchronous = OFF;
。
PRAGMA cache_size
はるかに大きな数に増やします。これにより、メモリにキャッシュされるページ数が増加します。注:cache_size
は接続ごとの設定です。
行ごとに1つのトランザクションではなく、すべての挿入を1つのトランザクションにラップします。
PRAGMA synchronous = OFF;
ます。ここの回答で提案されているいくつかのプラグマをテストしました:
synchronous = OFF
journal_mode = WAL
journal_mode = OFF
locking_mode = EXCLUSIVE
synchronous = OFF
+ locking_mode = EXCLUSIVE
+journal_mode = OFF
トランザクション内のさまざまな数の挿入に対する私の数値は次のとおりです。
バッチ サイズを大きくすると、実際のパフォーマンスが向上しますが、ジャーナル、同期、排他ロックの取得をオフにすると、わずかな向上が得られます。約 110k 付近のポイントは、ランダムなバックグラウンド ロードがデータベースのパフォーマンスにどのように影響するかを示しています。
journal_mode=WAL
また、これはデフォルトの優れた代替手段であることも言及する価値があります。ある程度の利益は得られますが、信頼性は低下しません。
RE:「データの各行に対して挿入ステートメントを生成するより高速な方法はありますか?」
最初に:Sqlite3の仮想テーブルAPIを利用して、2つのSQLステートメントに削減します。
create virtual table vtYourDataset using yourModule;
-- Bulk insert
insert into yourTargetTable (x, y, z)
select x, y, z from vtYourDataset;
ここでの考え方は、ソースデータセットを読み取り、それを仮想テーブルとしてSQliteに提示するCインターフェイスを実装してから、ソースからターゲットテーブルへのSQLコピーを一度に実行することです。それは実際よりも難しいように聞こえます、そして私はこの方法で大幅な速度の改善を測定しました。
2番目:ここで提供される他のアドバイス、つまりプラグマ設定とトランザクションの利用を利用します。
3番目:おそらく、ターゲットテーブルのインデックスの一部を廃止できるかどうかを確認してください。そうすれば、sqliteは挿入された行ごとに更新するインデックスが少なくなります
一括挿入する方法はありませんが、大きなチャンクをメモリに書き込んでからデータベースにコミットする方法はあります。C / C ++ APIの場合は、次のようにします。
sqlite3_exec(db、 "BEGIN TRANSACTION"、NULL、NULL、NULL);
...(INSERTステートメント)
sqlite3_exec(db、 "COMMIT TRANSACTION"、NULL、NULL、NULL);
dbがデータベースポインタであると仮定します。
適切な妥協案は、INSERTS を BEGIN の間にラップすることです。そして終わり; キーワードすなわち:
BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;
データのサイズと使用可能な RAM の量に応じて、ディスクへの書き込みではなくオールインメモリ データベースを使用するように sqlite を設定することで、最高のパフォーマンス向上の 1 つが発生します。
インメモリ データベースの場合、ファイル名引数として NULL を渡し、TEMP_STORE が適切に定義されていることを確認しますsqlite3_open
。
(上記のテキストはすべて、別の sqlite 関連の質問に対する私自身の回答から抜粋したものです)
これは、ワン ショット ロング インポートに適した組み合わせであることがわかりました。
.echo ON
.read create_table_without_pk.sql
PRAGMA cache_size = 400000; PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF; PRAGMA locking_mode = EXCLUSIVE; PRAGMA count_changes = OFF; PRAGMA temp_store = MEMORY; PRAGMA auto_vacuum = NONE;
.separator "\t" .import a_tab_seprated_table.txt mytable
BEGIN; .read add_indexes.sql COMMIT;
.exit
ソース: http://erictheturtle.blogspot.be/2009/05/fastest-bulk-import-into-sqlite.html
追加情報: http://blog.quibb.org/2010/08/fast-bulk-inserts-into-sqlite/
一度だけ挿入する場合は、汚いトリックがあるかもしれません。
アイデアは単純です。最初にメモリ データベースに挿入し、次にバックアップして、最後に元のデータベース ファイルに復元します。
詳細な手順はブログに書きました。:)
私はこの方法で一括挿入を行います:
colnames = ['col1', 'col2', 'col3']
nrcols = len(colnames)
qmarks = ",".join(["?" for i in range(nrcols)])
stmt = "INSERT INTO tablename VALUES(" + qmarks + ")"
vals = [[val11, val12, val13], [val21, val22, val23], ..., [valn1, valn2, valn3]]
conn.executemany(stmt, vals)
colnames must be in the order of the column names in the table
vals is a list of db rows
each row must have the same length, and
contain the values in the correct order
Note that we use executemany, not execute