Как 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")
}
}