データベースの最適化に取り組み、データベースを db と db2 の 2 つのデータベースに分割しました。優先度の低いバックグラウンド スレッドが db2 に挿入されています。db のクエリの一部は db2 と結合されているため、db2 を db にアタッチする必要があります。すべてをマルチスレッドにしたいので、WAL を有効にします。
SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath, ...);
db.enableWriteAheadLogging();
db.execSQL("attach " + db2path + " as db2");
この問題を理解するために、単純な 2 スレッド テストを実行します。最初のスレッドは db に行を挿入し、2 番目のスレッドは db から選択しています。各スレッドは、前のループからの時間の差分と、データベース内にいた時間を出力します。
thread 1 loop: | thread 2 loop:
t1 = getTime() | t1 = getTime()
db2.execSQL("insert into ...."); | db2.execSQL("select ....");
t2 = t3 | t2 = t3
t3 = getTime() | t3 = getTime()
log("i: "+(t3-t1)+", delta: "+(t2-t1)) | log("s: "+(t3-t1)+", delta: "+(t2-t1))
選択スレッドが挿入スレッドをブロックしていることがわかります。これは、巨大な(そして遅い)選択と小さな挿入を行うことで強調できます。挿入時間とデルタがほぼ選択時間まで増加することがわかります。遅いスレッドを実行しないと、挿入スレッドが大幅に高速化されます。
SQLiteDatabase のソース コードを掘り下げると、次の行が見つかりましたSQLiteDatabase#enableWriteAheadLogging()
。
// make sure this database has NO attached databases because sqlite's write-ahead-logging
// doesn't work for databases with attached databases
if (mHasAttachedDbsLocked) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "this database: " + mConfigurationLocked.label
+ " has attached databases. can't enable WAL.");
}
return false;
}
今私の質問に:
コメントの意味は何ですか?正確に何が機能しないのですか?取り残された古いコードですか?ATTACH DATABASE ( https://www.sqlite.org/lang_attach.html ) のドキュメントは、ATTACH + WAL が OK であることを明示的に示しています (小さな警告があります)。
Android バインディング コードが SQLite の内部問題から私たちを守ろうとするのはなぜですか? 私の見方では、それは薄い界面層であるはずです。
編集: 私はこれをAOSP issue trackerのバグとして報告しました。そこに回答が表示された場合に更新されます。