55

sqlite3データベースにロードしたい約30000行のデータのファイルがあります。データの各行に対して挿入ステートメントを生成するよりも速い方法はありますか?

データはスペースで区切られ、sqlite3テーブルに直接マップされます。ボリュームデータをデータベースに追加するための一括挿入方法はありますか?

それが組み込まれていない場合、誰かがこれを行うためのいくつかの明らかに素晴らしい方法を考案しましたか?

APIからそれを行うC++の方法はありますか?

4

12 に答える 12

61
  • すべての INSERT をトランザクションでラップします。ユーザーが 1 人であっても、はるかに高速です。
  • 準備済みステートメントを使用します。
于 2008-12-12T20:54:50.207 に答える
43

.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

于 2009-04-17T10:15:44.460 に答える
23

また、いくつかのパラメーターを微調整して、速度を上げることもできます。具体的には、おそらく必要ですPRAGMA synchronous = OFF;

于 2008-12-12T21:11:12.670 に答える
21
  • PRAGMA cache_size はるかに大きな数に増やします。これにより、メモリにキャッシュされるページ数が増加します。注:cache_sizeは接続ごとの設定です。

  • 行ごとに1つのトランザクションではなく、すべての挿入を1つのトランザクションにラップします。

  • コンパイルされたSQLステートメントを使用して挿入を行います。
  • 最後に、すでに述べたように、完全なACID準拠を放棄する場合は、を設定しPRAGMA synchronous = OFF;ます。
于 2008-12-13T00:25:00.220 に答える
21

ここの回答で提案されているいくつかのプラグマをテストしました:

  • synchronous = OFF
  • journal_mode = WAL
  • journal_mode = OFF
  • locking_mode = EXCLUSIVE
  • synchronous = OFF+ locking_mode = EXCLUSIVE+journal_mode = OFF

トランザクション内のさまざまな数の挿入に対する私の数値は次のとおりです。

バッチ サイズを大きくすると、実際のパフォーマンスが向上しますが、ジャーナル、同期、排他ロックの取得をオフにすると、わずかな向上が得られます。約 110k 付近のポイントは、ランダムなバックグラウンド ロードがデータベースのパフォーマンスにどのように影響するかを示しています。

journal_mode=WALまた、これはデフォルトの優れた代替手段であることも言及する価値があります。ある程度の利益は得られますが、信頼性は低下しません。

C# コード。

于 2019-10-24T18:43:38.417 に答える
13

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は挿入された行ごとに更新するインデックスが少なくなります

于 2010-06-17T08:18:05.767 に答える
6

一括挿入する方法はありませんが、大きなチャンクをメモリに書き込んでからデータベースにコミットする方法はあります。C / C ++ APIの場合は、次のようにします。

sqlite3_exec(db、 "BEGIN TRANSACTION"、NULL、NULL、NULL);

...(INSERTステートメント)

sqlite3_exec(db、 "COMMIT TRANSACTION"、NULL、NULL、NULL);

dbがデータベースポインタであると仮定します。

于 2010-01-20T19:21:53.110 に答える
4

適切な妥協案は、INSERTS を BEGIN の間にラップすることです。そして終わり; キーワードすなわち:

BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;
于 2011-09-08T09:53:46.943 に答える
3

データのサイズと使用可能な RAM の量に応じて、ディスクへの書き込みではなくオールインメモリ データベースを使用するように sqlite を設定することで、最高のパフォーマンス向上の 1 つが発生します。

インメモリ データベースの場合、ファイル名引数として NULL を渡し、TEMP_STORE が適切に定義されていることを確認しますsqlite3_open

(上記のテキストはすべて、別の sqlite 関連の質問に対する私自身の回答から抜粋したものです)

于 2008-12-16T00:34:19.277 に答える
3

これは、ワン ショット ロング インポートに適した組み合わせであることがわかりました。

.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/

于 2015-11-18T09:16:51.110 に答える
1

一度だけ挿入する場合は、汚いトリックがあるかもしれません。

アイデアは単純です。最初にメモリ データベースに挿入し、次にバックアップして、最後に元のデータベース ファイルに復元します。

詳細な手順はブログに書きました。:)

于 2009-12-28T15:03:17.413 に答える
0

私はこの方法で一括挿入を行います:

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
于 2020-08-23T18:35:12.973 に答える