SQLite:具有附加数据库

时间:2016-08-25 15:21:17

标签: android multithreading sqlite wal

在数据库优化方面,我们将数据库拆分为两个数据库: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内部问题的影响?我看待它的方式,它应该是一个薄的界面层。

  3. 编辑:我将此报告为AOSP issue tracker中的错误。如果答案出现在那里会更新。

1 个答案:

答案 0 :(得分:0)

WAL允许读者和作者同时,但只能从不同的连接。您永远不应该使用来自多个线程的相同连接("use strict"; var async = require('async'); var kafkaRest = require('kafka-rest'); var topicName = "avro-test"; var valueSchema = new kafkaRest.AvroSchema({ "name": "UserInfo", "type": "record", "fields": [ { "name": "id", "type": "int" }, { "name": "name", "type": "string" }] }); var kafka = new kafkaRest({"url": "http://localhost:8082"}); var target = kafka.topic(topicName); // Avro key and value schema. for(var i = 0; i <= 1005; i++) { var line = {'id': 1, 'name': 'Bob '}; target.produce(valueSchema, line, handleResponse); } function handleResponse( err, res) { if (err) { console.log("Error producing messages " + err); } } 对象)。

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

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

  2. 有时,Android框架会变得聪明。但您可以手动执行SQLiteDatabase