有人可以解释一下使用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遭遇。我可以去研究任何想法或方向吗?谢谢!
答案 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>
如果是,请在交易后删除INDEX
和CREATE
。
一次选择
在生成新数据时,我没有看到使用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没有打开错误。如果对如何改进这一点有任何建议,请告诉我。