Как iOS запрос (SELECT) параллелизма с FMDB?

Я хочу читать параллелизм данных из базы данных (sqlite3), но это стоит больше времени, чем с одним потоком. Устройство iPhone SE и iPhone6 ​​plus. Мой код следующий:

Создать таблицу базы данных:

fileprivate var dbPath: String!
fileprivate var db: FMDatabase?

/// Create Table
dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/" + "tmp.db";
if let dbFh = FMDatabase(path: dbPath) {
    dbFh.open()
    if dbFh.tableExists("test") {
        db = dbFh
    } else if dbFh.executeUpdate("create table test (a text, b text, c integer, d double, e double)", withArgumentsIn: []) {
        db = dbFh
    }
}
/// Insert Data
transaction(count: 5000)

Вставить данные:

fileprivate func transaction(count: Int = 10) {

    guard count >= 0 else {
        return
    }

    guard let dbFh = db else {
        return
    }

    if !dbFh.open() {
        return
    }

    let image = UIImage(named: "image02")!
    let imgData = UIImageJPEGRepresentation(image, 1)!

    dbFh.beginTransaction()

    for index in 0..<count {
        if !dbFh.executeUpdate("insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)", withArgumentsIn: ["index\(index)", imgData, index, index, index]) {
            print("err:", dbFh.lastErrorMessage())
            break
        }
    }

    dbFh.commit()

    if !dbFh.close() {
        return
    }
}

Чтение данных из базы данных одним потоком, и это стоит около 6 секунд:

func singleThreadRead() {
    let queue0 = FMDatabaseQueue(path: dbPath)
    queue0?.inDatabase({ (db) in
        let startTime = CFAbsoluteTimeGetCurrent()
        if let result = db?.executeQuery("select * from test limit 5000", withArgumentsIn: []) {
            while result.next() {
            }
            let endTime = CFAbsoluteTimeGetCurrent()
            // About 6s
            let duration = endTime - startTime
        } else {
            print("queue0 query err ")
        }
    })
}

Чтение данных из базы данных двумя потоками, но это стоит около 18 секунд, а не около 3 секунд:

func doubleThreadRead() {

    let queue0 = FMDatabaseQueue(path: dbPath)
    let queue1 = FMDatabaseQueue(path: dbPath)

    let startTime = CFAbsoluteTimeGetCurrent()
    var endTime0: Double = 0
    var endTime1: Double = 0

    let group = DispatchGroup()

    group.enter()
    DispatchQueue.global().async {
        queue0?.inDatabase({ (db) in
            if let result = db?.executeQuery("select * from test limit 2500", withArgumentsIn: []) {
                while result.next() {
                }
            } else {
            }
            endTime0 = CFAbsoluteTimeGetCurrent()
            group.leave()
        })
    }

    group.enter()
    DispatchQueue.global().async {
        queue1?.inDatabase({ (db) in
            if let result = db?.executeQuery("select * from test limit 2500 offset 2500", withArgumentsIn: []) {
                while result.next() {
                }
            } else {
            }
            endTime1 = CFAbsoluteTimeGetCurrent()
            group.leave()
        })
    }

    group.notify(queue: .main) {
        let endTime = (endTime0 > endTime1) ? endTime0 : endTime1
        // About 18s
        let duration = endTime - startTime
    }
}

ДОБАВЛЯТЬ:

Теперь я использую API sqlite, но это вызывает тот же результат.

var sdb :OpaquePointer? = nil
var sdb0 :OpaquePointer? = nil

func doubleThreadRead() {

    let group = DispatchGroup()

    let flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX

    group.enter()
    DispatchQueue.global().async {

        if sqlite3_open_v2(NSString(string: self.dbPath).fileSystemRepresentation, &self.sdb, flags, nil) == SQLITE_OK {
            print("open success")
        } else {
            print("open fail")
        }

        let startTime = CFAbsoluteTimeGetCurrent()

        var statement :OpaquePointer? = nil
        let sql = "select * from test limit 2500 offset 2500"
        sqlite3_prepare_v2(self.sdb!, (sql as NSString).utf8String, -1, &statement, nil)

        while sqlite3_step(statement) == SQLITE_ROW {
        }
        sqlite3_finalize(statement)

        sqlite3_close_v2(self.sdb)

        let endTime = CFAbsoluteTimeGetCurrent()

        print("db duration = ", endTime - startTime)

        group.leave()
    }

    group.enter()
    DispatchQueue.global().async {

        if sqlite3_open_v2(NSString(string: self.dbPath).fileSystemRepresentation, &self.sdb0, flags, nil) == SQLITE_OK {
            print("open success")
        } else {
            print("open fail")
        }

        let startTime = CFAbsoluteTimeGetCurrent()

        var statement :OpaquePointer? = nil
        let sql = "select * from test limit 2500"
        sqlite3_prepare_v2(self.sdb0!, (sql as NSString).utf8String, -1, &statement, nil)

        while sqlite3_step(statement) == SQLITE_ROW {
        }
        sqlite3_finalize(statement)

        sqlite3_close_v2(self.sdb0)

        let endTime = CFAbsoluteTimeGetCurrent()

        print("db0 duration = ", endTime - startTime)

        group.leave()
    }

    group.notify(queue: .main) {
        print("end")
    }
}

0 ответов

Другие вопросы по тегам