14

有人能解释一下使用 FMDB 在 iPhone 上插入大量数据的最佳方法是什么吗?我看到了使用 beginTransaction 命令之类的东西。老实说,我不确定 this 或 setShouldCacheStatements 是做什么的。到目前为止,我遵循了我的同事所做的代码,这就是它的样子:

BOOL oldshouldcachestatements = _db.shouldCacheStatements;
[_db setShouldCacheStatements:YES];
[_db beginTransaction];
NSString *insertQuery = [[NSString alloc] initWithFormat:@"INSERT INTO %@ values(null, ?, ?, ?, ?, ?, ?, ?);", tableName];
[tableName release];
BOOL success;

bPtr += 2;
int *iPtr = (int *)bPtr;
int numRecords = *iPtr++;

for (NSInteger record = 0; record < numRecords; record++) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // Some business logic to read the binary stream  

    NSNumber *freq = aFreq > 0 ? [NSNumber numberWithDouble:100 * aFreq / 32768]: [NSNumber numberWithDouble:-1.0];

    // these fields were calculated in the business logic section
    success = [_db executeUpdate:insertQuery,
               cID,                                                                                                   
               [NSNumber numberWithInt:position],                                                                       
               [NSString stringWithFormat:@"%@%@", [self stringForTypeA:typeA], [self stringForTypeB:typeB]],     // methods are switch statements that look up the decimal number and return a string
               [NSString stringWithFormat:@"r%i", rID],                                                               
               [self stringForOriginal:original],                                                                    
               [self stringForModified:modified],                                                                    
               freq];

    [pool drain];
}
[outerPool drain];

[_db commit];
[_db setShouldCacheStatements:oldshouldcachestatements];

这是我能做到的最快速度吗?写是sqlite的限制吗?我看到了这个:http ://www.sqlite.org/faq.html#q19并且不确定这个实现是否是最好的 fmdb,或者我是否可以做任何其他事情。其他一些同事提到了一些关于批量插入和优化的事情,但我不确定这意味着什么,因为这是我第一次遇到 sqlite。有什么想法或方向我可以研究吗?谢谢!

4

2 回答 2

39

首先,在大多数情况下,如果您没有完全错误地使用 sqlite3,您不必担心它的性能。

以下内容可提高INSERT语句的性能:

交易

正如您已经提到的,交易是最重要的功能。特别是如果您有大量查询,事务将使您的 s 加速INSERT~10 倍

杂注配置

Sqlite3 提供了几种机制,可以在最坏的情况下避免数据库损坏。在某些情况下,这不是必需的。在其他情况下,这是绝对必要的。以下 sqlite3 命令可能会加快您的INSERT语句速度。您的应用程序的正常崩溃不会损坏数据库,但操作系统崩溃可能会。

PRAGMA synchronous=OFF -- may cause corruption if the OS fails
PRAGMA journal_mode=MEMORY -- Insert statements will be written to the disk at the end of the transaction
PRAGMA cache_size = 4000 -- If your SELECTs are really big, you may need to increase the cache
PRAGMA temp_store=MEMORY -- Attention: increases RAM use

停用指标

任何 SQL 索引都会减慢INSERT语句的速度。检查您的表是否有一些索引:

.indices <table_name>

如果是,则在事务后DROPINDEX和它。CREATE

一选一

当您生成新数据时,我看不到使用 BULK 插入的方法。但是,您可以收集数据并只执行一条INSERT语句。这可能会显着提高您的性能,但也会增加失败的可能性(例如语法)。一个 hack 遇到另一个 hack:由于 sqlite3 不直接支持这一点,因此您必须使用 UNION 命令相应地收集所有插入语句。

INSERT INTO 'tablename'
      SELECT 'data1' AS 'column1', 'data2' AS 'column2'
UNION SELECT 'data3', 'data4'
UNION SELECT 'data5', 'data6'
UNION SELECT 'data7', 'data8'

语句缓存

我建议避免使用语句缓存,因为此功能存在未解决的问题(据我所知,它不会显着影响性能)。

内存管理

我想提的最后一点是关于 ObjC。与基本操作相比,内存管理需要非常非常多的时间。也许你可以避免一些stringWithFormat:numberWithDouble:通过在循环外准备这些变量。

概括

总而言之,如果你简单地使用transactions,我认为你不会对 sqlite3 的速度有问题。

于 2012-08-07T19:28:11.340 回答
9

我发现很难找到一个关于如何快速插入多行的具体代码示例。在对 FMDB 进行了大量实验并得到上述答案的帮助之后,这就是我目前正在使用的:

[_objectController.dbQueue inDatabase:^(FMDatabase *db)
{
    [db open];
    [db setShouldCacheStatements:YES];

    NSArray *documentsJSONStream = responseObject[@"details"][@"stream"];

    static NSString *insertSQLStatment = @"INSERT INTO documents (`isShared`,`thumbnailURLString`,`userID`,`version`,`timestamp`,`tags`,`title`,`UDID`,`username`,`documentURLString`,`shareURLString`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    [db beginTransaction];
    for (NSDictionary *dJ in documentsJSONStream)
    {
        [db executeUpdate:insertSQLStatment withArgumentsInArray:@[dJ[@"isShared"],dJ[@"thumbnailURLString"],dJ[@"userID"],dJ[@"version"],dJ[@"timestamp"],dJ[@"tags"],dJ[@"title"],dJ[@"UDID"],dJ[@"username"],dJ[@"documentURLString"],dJ[@"shareURLString"]]];
    }
    [db commit];
    [db close];
 }];

使用 inTransaction 给了我奇怪的 FMDB is not open 错误。如果有任何关于如何改进这一点的建议,请告诉我。

于 2015-02-02T10:16:05.453 回答