【问题标题】:Objective-C - FMDB - Large SQLite Dump ImportObjective-C - FMDB - 大型 SQLite 转储导入
【发布时间】:2014-05-28 17:50:42
【问题描述】:

我有一个很大的 SQLite 文件,里面装满了用于创建我的数据库表和插入所有记录的查询。该文件相当大,运行 SQL 文件所需的时间似乎比我预期的要长。

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

最好的方法是什么?

【问题讨论】:

    标签: objective-c sqlite fmdb


    【解决方案1】:

    如果使用FMDatabase 进行大量单独的UPDATEINSERT 调用,请考虑在开头使用beginTransaction,在结尾使用commit

    [db beginTransaction];
    // do all of your updates
    [db commit];
    

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

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

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


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

    就个人而言,使用第三方 SQL 解析例程让我很紧张,所以我倾向于直接调用 SQLite 函数sqlite3_exec。为此,您可以使用 FMDB 的sqliteHandle 方法从FMDatabase 对象访问sqlite3 指针,然后直接与sqlite3_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]);
    }
    

    我必须承认,将批量 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];
    

    【讨论】:

    • 这是一些非常好的建议...但是我该如何处理大型 SQL 文件呢?
    • 我最初确实使用 JSON 来请求所有数据,问题是它需要很长时间才能下拉。所以我不得不考虑另一种方式。
    • @rckehoe 够公平的。如果 SQL 文件小得多(如果有的话),我会感到惊讶。我想知道有多少性能问题实际上是在传输时间上,有多少问题是没有事务(BEGIN TRANSACTIONCOMMIT 如果通过 SQL 进行,beginTransactioncommit 如果使用 FMDB界面)。看到在更新过程中通过使用事务可以实现多少性能改进,这确实是非常令人惊讶的。我是一个实用主义者,所以如果使用 SQL 文件有帮助,那很好,但如果这真的是问题,我会感到惊讶。
    • 好的...所以这是个大问题...我的 SQL 中有语法错误。我没有意识到你必须通过加倍而不是 \" 来逃避 "。除此之外,您的代码效果很好!非常感谢您的帮助!
    • 另外,我也在使用事务,下载/解析一切只需要 10-15 秒。你摇滚!!
    猜你喜欢
    • 1970-01-01
    • 2013-02-09
    • 2012-05-23
    • 1970-01-01
    • 2012-12-18
    • 2011-01-29
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多