在iPhone上将多行插入sqlite db的最快方法

时间:2012-08-02 19:06:52

标签: iphone fmdb

有人可以解释一下使用FMDB在iPhone上插入大量数据的最佳方法是什么?我看到使用beginTransaction命令之类的东西。老实说,我不确定这个或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遭遇。我可以去研究任何想法或方向吗?谢谢!

2 个答案:

答案 0 :(得分:38)

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

以下内容提升了INSERT语句的性能:

<强>交易

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

PRAGMA配置

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>

如果是,请在交易后删除INDEXCREATE

一次选择

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

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

声明缓存

我建议避免使用语句缓存,因为有一个unfixed issue具有此功能(据我所知,它不会显着影响性能)。

内存管理

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

<强>摘要

总而言之,如果你只是使用交易,我认为你不会对sqlite3的速度有任何问题。

答案 1 :(得分:8)

我发现很难找到一个关于如何快速插入多行的具体代码示例。经过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没有打开错误。如果对如何改进这一点有任何建议,请告诉我。