Objective-C - FMDB - 大型 SQLite 转储导入

rck*_*hoe 2 sqlite objective-c fmdb

我有一个大型 SQLite 文件,其中充满了用于创建数据库表并插入所有记录的查询。该文件相当大,并且运行 SQL 文件似乎花费的时间比我预期的要长得多。

我正在将 FMDB 用于我正在开发的 iPad 应用程序,我真的想用新的数据库文件替换当前的数据库文件,但我不确定 sql 文件是否与数据库文件相同。它不包含任何相同的标头信息等......

执行此操作的最佳方法是什么?

Rob*_*Rob 5

如果使用 进行大量单独的UPDATE或INSERT调用,请考虑在开始和结束时FMDatabase执行以下操作:beginTransactioncommit

[db beginTransaction];
// do all of your updates
[db commit];
Run Code Online (Sandbox Code Playgroud)

或者,如果使用FMDatabaseQueue,请使用inTransaction:

[databaseQueue inTransaction:^(FMDatabase *db , BOOL *rollback) { 
    // do all of your updates
}];
Run Code Online (Sandbox Code Playgroud)

如果您不使用其中之一,它将在每次插入后提交,这会使速度慢得多。如果添加大量行,差异可能会很大(例如,当添加/更新大量小记录时,我发现性能差异有两个数量级)。


上面假设您正在尝试执行一系列单独的 SQL 命令。如果所有内容都在一个文件中(例如.dump输出),则 FMDB 历史上没有一个接口可以执行此操作(尽管有一个 SQLite 函数 ,sqlite3_exec可以精确执行此操作)。最近添加了一个extra名为 的文件夹FMDatabaseSplitter,它尝试将一长串 SQL 拆分为单独的调用,然后您可以单独调用它们。

就我个人而言,使用第三方 SQL 解析例程让我感到紧张,所以我倾向于sqlite3_exec直接调用 SQLite 函数。为此,您可以使用 FMDB方法sqlite3从对象访问指针,然后直接将其与函数结合使用:FMDatabasesqliteHandlesqlite3_exec

NSError *error = nil;
NSString *dumpSQL = [NSString stringWithContentsOfFile:dumpFilePath encoding:NSUTF8StringEncoding error:&error];
NSAssert(dumpSQL, @"Loading of SQL failed: %@", error);

int rc = sqlite3_exec(db.sqliteHandle, [dumpSQL UTF8String], NULL, NULL, NULL);
if (rc != SQLITE_OK) {
    NSLog(@"sqlite3_exec error: %@", [db lastErrorMessage]);
}
Run Code Online (Sandbox Code Playgroud)

我必须承认,仅仅将批量 SQL 导入到应用程序的数据库中让我有点紧张。如果您不非常小心,SQL 中的一个无心错误可能会破坏整个安装库的应用程序。我宁愿看到应用程序从服务器请求 JSON 或 XML 源,然后自行进行更新,但如果您想使用输出.dump通过 FMDB 更新应用程序的数据库,这是一种方法。


FMDB v2.3 引入了一个包装器,sqlite3_exec称为executeStatements:

BOOL success;

NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"
                 "create table bulktest2 (id integer primary key autoincrement, y text);"
                 "create table bulktest3 (id integer primary key autoincrement, z text);"
                 "insert into bulktest1 (x) values ('XXX');"
                 "insert into bulktest2 (y) values ('YYY');"
                 "insert into bulktest3 (z) values ('ZZZ');";

success = [db executeStatements:sql];
Run Code Online (Sandbox Code Playgroud)