1

在数据库优化方面,我们将数据库拆分为两个数据库:db 和 db2。低优先级后台线程正在插入 db2。db 上的一些查询是和 db2 连接的,所以我们需要将 db2 附加到 db。我们启用 WAL 是因为希望它都是多线程的。

SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath, ...);
db.enableWriteAheadLogging();
db.execSQL("attach " + db2path + " as db2");

为了理解这个问题,我们运行一个简单的两线程测试。第一个线程将行插入到 db 中,第二个线程正在从 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;
}

现在我的问题:

  1. 评论的意义是什么?究竟是什么行不通?是遗留了一些旧代码吗?ATTACH DATABASE ( https://www.sqlite.org/lang_attach.html ) 的文档明确表明 ATTACH + WAL 是可以的(有一点警告。)

  2. 为什么 Android 绑定代码试图保护我们免受 SQLite 内部问题的影响?在我看来,它应该是一个薄的界面层。

编辑:我将此报告为AOSP 问题跟踪器中的一个错误。如果那里出现答案,将更新。

4

1 回答 1

0

WAL 允许读者和作者同时,但只能来自不同的连接。您永远不应该使用SQLiteDatabase来自多个线程的相同连接(对象)。

WAL 设置是永久的;不需要每次打开数据库后都执行。

  1. 评论的意思正是它所说的。(没有人保证这个评论是正确的。)

  2. 有时,Android 框架试图变得聪明。但是您可以PRAGMA journal_mode = WAL手动执行。

于 2016-08-25T17:59:00.977 回答