大量のデータ(550万行)をSQLiteデータベースファイルに一括ロードしようとしています。 INSERTによる読み込みは非常に遅いようですので、sqlite3コマンドラインツールと.importコマンドを使用しようとしています。
手でコマンドを入力すれば完全に機能しますが、スクリプト(.batファイルまたはpython script;私はWindowsマシンでの作業)。
コマンドラインで発行するコマンドは次のとおりです。
> sqlite3 database.db
sqlite> CREATE TABLE log_entry ( <snip> );
sqlite> .separator "\t"
sqlite> .import logfile.log log_entry
しかし、batファイルまたはpythonスクリプト。
私は次のようなことを試みてきました:
sqlite3 "database.db" .separator "\t" .import logfile.log log_entry
echo '.separator "\t" .import logfile.log log_entry' | sqlite3 database.db
どうにかしてこれを行うことができますか?
次のように、sqliteコマンドラインプログラムに入力する行を含むテキストファイルを作成します。
CREATE TABLE log_entry(); 。separator "\ t" 。import logfile.log log_entry
そして、sqlite3 database.db < commands.txt
を呼び出すだけです
あるいは、 heredocimport.shを使用して、すべてを1つのシェルスクリプトファイルに入れることができます(したがって、メンテナンスが簡単になります)。
#!/bin/bash --
sqlite3 -batch $1 <<"EOF"
CREATE TABLE log_entry ( <snip> );
.separator "\t"
.import logfile.log log_entry
EOF
...そしてそれを実行します:
import.sh database.db
これにより、1つのスクリプトファイルのみを保守しやすくなります。ちなみに、Windowsで実行する必要がある場合は、 Power Shellはheredocも備えています
さらに、このアプローチは、スクリプトパラメーターのサポート不足に対処するのに役立ちます。 bash変数を使用できます:
#!/bin/bash --
table_name=log_entry
sqlite3 -batch $1 <<EOF
CREATE TABLE ${table_name} ( <snip> );
.separator "\t"
.import logfile.log ${table_name}
EOF
または、次のようなトリックを行うこともできます。
#!/bin/bash --
table_name=$2
sqlite3 -batch $1 <<EOF
CREATE TABLE ${table_name} ( <snip> );
.separator "\t"
.import logfile.log ${table_name}
EOF
...そして実行します:import.sh database.db log_entry
Sqlite3シェルアプリに通常入力するすべてのコマンドを含む別のテキストファイルを作成します。
CREATE TABLE log_entry ( <snip> );
.separator "\t"
.import /path/to/logfile.log log_entry
たとえば、impscript.sqlとして保存します。
そのスクリプトでsqlite3シェルを呼び出すバッチファイルを作成します。
sqlite3.exe yourdatabase.db < /path/to/impscript.sql
バッチファイルを呼び出します。
補足説明-インポートするときは、トランザクションでINSERTをラップするようにしてください!これにより、瞬時に10.000%の速度が向上します。
最近、Firefoxのcookies.sqliteをテキストファイルに変換する際(ダウンロードツール用)に同様の問題が発生し、この質問に出くわしました。
私は単一のシェル行でそれをしたかったのですが、それは上記の問題に適用される私のソリューションになります:
echo -e ".mode tabs\n.import logfile.log log_entry" | sqlite3 database.db
しかし、私はまだその行をテストしていません。しかし、それは私が上記で言及したFirefoxの問題(Mac OSXのBash経由)でうまく機能しました:
echo -e ".mode tabs\nselect Host, case when Host glob '.*' then 'TRUE' else 'FALSE' end, path, case when isSecure then 'TRUE' else 'FALSE' end, expiry, name, value from moz_cookies;" | sqlite3 cookies.sqlite
sqlite3 abc.db ".read scriptname.sql"
この時点で、他に何を追加できるかわからない。nad2000によって提案されたbashスクリプトにunix環境変数を追加するのに苦労した。
これを実行する:
bash dbmake.sh database.db <(sed '1d' $DATA/logfile.log | head -n 1000)
回避策としてstdinからインポートする必要があり、この解決策が見つかりました:
sqlite3 $1 <<"EOF"
CREATE TABLE log_entry;
EOF
sqlite3 -separator $'\t' $1 ".import $2 log_entry"
2番目のsqlite3行を追加することで、Unixから$ 2を.import、フルパスなどのファイルパラメーターに渡すことができました。
Windowsでは、これは機能するはずです。
(echo CREATE TABLE log_entry ( <snip> ); & echo .separator "\t" & echo .import logfile.log log_entry) | sqlite3.exe database.db
この特定のコマンドはテストしていませんが、複数のコマンドをパイプ処理するというこの問題を解決しようとする私自身の追求から、エコーされたコマンドを括弧で囲むことが重要であることがわかりました。そうは言っても、これらの文字の一部をエスケープするには、上記のコマンドを微調整する必要があるかもしれません。例えば:
(echo CREATE TABLE log_entry ^( ^<snip^> ^); & echo .separator "\t" & echo .import logfile.log log_entry) | sqlite3.exe database.db
この場合、エスケープが必要かどうかはわかりませんが、括弧が囲む括弧と競合する可能性が高いため、「less」と「大なり」記号は、通常、入力または出力として解釈されますが、これも競合する可能性があります。キャラクターのエスケープの広範なリストはここにあります: http://www.robvanderwoude.com/escapechars.php