在我的iPhone应用程序上,我正在使用SQLite数据库,为此我依赖fmdb。 在使用iOS 5的iPhone上,初始数据库访问最多需要10秒,但在iOS 6上则需要30秒到2分40秒(在iPhone 4和4S上,在iPhone 5上需要大约15到20秒)。 我注意到的一件事是,时间总是一致的,如果在一部手机上需要60秒,它总是需要60秒。
有没有理由在iOS 6中使用fmdb比在iOS 5上慢?有没有比fmdb更好的替代方案?
就代码而言,这是我正在做的一个示例:
获取数据
+ (NSMutableArray*) getLevadas
{
FMDatabase *db = [DBAdapter getDB];
if([db open])
{
FMResultSet *result = [db executeQuery:@"SELECT Levada.Levada_id, Levada.Nome, a.Nome as Inicio, b.Nome as Fim, Dificuldade.NomePT as DificuldadePT, Dificuldade.NomeES as DificuldadeES, Dificuldade.NomeEN as DificuldadeEN, Altitude, Distancia, DescricaoPT, DescricaoEN, DescricaoES, Latitude, Longitude, Autocarro, Levada.dataModificado, a.Sector, Levada.Duracao, b.Sector as SectorFim, GROUP_CONCAT(DISTINCT PalavrasChave.NomePT) as PalavrasChavePT, GROUP_CONCAT(DISTINCT PalavrasChave.NomeEN) as PalavrasChaveEN, GROUP_CONCAT(DISTINCT PalavrasChave.NomeES) as PalavrasChaveES, GROUP_CONCAT(DISTINCT Equipamento.NomeEN) as EquipamentoEN, GROUP_CONCAT(DISTINCT Equipamento.NomePT) as EquipamentoPT, GROUP_CONCAT(DISTINCT Equipamento.NomeES) as EquipamentoES, Levada.Coordenadas, Levada.LongitudeFim, Levada.LatitudeFim, Levada.PontosInteresse, GROUP_CONCAT(DISTINCT Fotos.url) as Fotos FROM Levada, Localizacoes as a, Localizacoes as b, Dificuldade, Levada_has_PalavrasChave, PalavrasChave, Levada_has_Equipamento, Equipamento, Fotos WHERE ((Inicio_id = a.Localizacoes_id) AND (Fim_id = b.Localizacoes_id) AND (Levada.Dificuldade_id = Dificuldade.Dificuldade_id) AND (Levada.Levada_id = Levada_has_PalavrasChave.Levada_id) AND (PalavrasChave.PalavrasChave_id = Levada_has_PalavrasChave.PalavrasChave_id) AND (Levada.Levada_id = Levada_has_Equipamento.Levada_id) AND (Levada_has_Equipamento.Equipamento_id = Equipamento.Equipamento_id) AND Levada.Levada_id = Fotos.idLevada) GROUP BY Levada.Levada_id ORDER BY Levada.Nome;"];
NSMutableArray *levadas = [[NSMutableArray alloc] init];
while ([result next])
{
Levada *l = [[Levada alloc] init];
[l ID:[NSNumber numberWithInt: [result intForColumn:@"Levada_id"]]];
[l Nome:[result stringForColumn:@"Nome"]];
[l Dificuldade:[result stringForColumn:[NSString stringWithFormat:@"Dificuldade%@", NSLocalizedString(@"lingua", NULL)]]];
[l Distancia:[result objectForColumnName:@"Distancia"]];
[l Duracao:[result stringForColumn:@"Duracao"]];
[l Inicio:[result stringForColumn:@"Inicio"]];
[l Fim:[result stringForColumn:@"Fim"]];
[l Altitude:[result stringForColumn:@"Altitude"]];
[l PalavrasChave:[[result stringForColumn:[NSString stringWithFormat:@"PalavrasChave%@", NSLocalizedString(@"lingua", NULL)]] stringByReplacingOccurrencesOfString:@"," withString:@", "]];
[l Descricao:[result stringForColumn:[NSString stringWithFormat:@"Descricao%@", NSLocalizedString(@"lingua", NULL)]]];
[l Fotos: [[result stringForColumn:@"Fotos"] componentsSeparatedByString:@","]];
[l Latitude:[NSNumber numberWithDouble:[[result stringForColumn:@"Latitude"] doubleValue]]];
[l LatitudeFim:[NSNumber numberWithDouble:[[result stringForColumn:@"LatitudeFim"] doubleValue]]];
[l Longitude:[NSNumber numberWithDouble:[[result stringForColumn:@"Longitude"] doubleValue]]];
[l LongitudeFim:[NSNumber numberWithDouble:[[result stringForColumn:@"LongitudeFim"] doubleValue]]];
[l Coordenadas:[result stringForColumn:@"Coordenadas"]];
[l Equipamento: [[result stringForColumn:[NSString stringWithFormat:@"Equipamento%@", NSLocalizedString(@"lingua", NULL)]] componentsSeparatedByString:@","]];
[l DataModificado:[result stringForColumn:@"dataModificado"]];
[l Sector: [result stringForColumn:@"Sector"]];
[l SectorFim: [result stringForColumn:@"SectorFim"]];
[l Autocarro: [result stringForColumn:@"Autocarro"]];
[levadas addObject:l];
}
[result close];
[db close];
return levadas;
}
return nil;
}
打开数据库
+ (FMDatabase*) getDB
{
[DBAdapter copyDatabaseIfNeeded];
FMDatabase *db = [FMDatabase databaseWithPath:[DBAdapter getDBPath]];
[db setLogsErrors:YES];
return db;
}
+ (void) copyDatabaseIfNeeded
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [DBAdapter getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success)
{
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"WalkMe.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
}
}
+ (NSString *) getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:@"WalkMe.sqlite"];
}
更新
以下是时间分析的屏幕截图:
从我可以收集到的最耗时的是[FMResultSet next]指令,更具体地说是FMDB下一代码中的rc = sqlite3_step([_statement statement]);
。所以我猜这个问题确实是SELECT语句。
更新2:
我尝试将SQL语句简化为 始终清理项目时仍需要花费太多时间。SELECT Levada_id FROM Levada
,并且在[FMResultSet next]
答案 0 :(得分:2)
花了一些时间详细介绍FMDB代码,没有什么可以解释那些类型的延迟。 FMDB是一个非常薄的包装器,几乎可以肯定不会对这种行为负责。还有足够的SQLite / FMDB用户,如果在iOS 6中实际存在与SQLite / FMDB相关的问题,我会感到非常惊讶。我想如果有的话我们现在会听到很多关于它的信息。< / p>
但是看一下你的SELECT语句,这似乎相当复杂,如果我要下注,如果问题实际上与数据库有关,我敢打赌这是延迟的来源。如果您单步执行代码,这将很容易验证。或者在之前和之后输入NSLog语句,你将获得带时间戳的日志语句,这可以解决问题。
最重要的是,假设问题实际上与数据库相关,那几乎肯定是SQLite问题。如果您使用sqlite3_xxx()
调用重写此函数以执行所有操作,您可能会看到相同的性能问题。话虽如此,我还没有看到FMDB / SQLite的任何性能问题转移到iOS6。如果iOS 6上的SQLite / FMDB存在广泛的性能问题,我也会认为我们会听到血腥的嚎叫。
我专注于通过SQLite的EXPLAIN放置sql语句,然后优化表,确保你有适当的索引或重组SQL。只需在计算机上的SQLite中打开数据库,然后尝试分析那里的查询。
就可能导致iOS 6与iOS 5上的这种性能问题的情况而言,我不熟悉它如何打开数据库的任何变化。
如果您的分析确认SQLite存在问题,或者更确切地说它与SQLite / FMDB完全无关,那将非常有趣。
<强>更新强>
我决定检查iOS 5.1.1和6.0.1中的SQLite配置之间是否有任何有趣的配置更改,但没有任何内容突然出现在我面前。 (一个不同的线程模型肯定会影响性能,但它们看起来是一样的。)iOS 6肯定会使用稍微更新的SQLite版本,但我怀疑这会对它产生负面影响。
Device: iPhone OS iOS: 5.1.1 SQLite Configuration: Version: 3.7.7 Threadsafe: Yes Options: ENABLE_FTS3: Yes ENABLE_FTS3_PARENTHESIS: Yes ENABLE_LOCKING_STYLE=1: Yes ENABLE_RTREE: Yes OMIT_AUTORESET: Yes OMIT_BUILTIN_TEST: Yes OMIT_LOAD_EXTENSION: Yes TEMP_STORE=1: Yes THREADSAFE=2: Yes
Device: iPhone OS iOS: 6.0.1 SQLite Configuration: Version: 3.7.13 Threadsafe: Yes Options: CURDIR: Yes ENABLE_FTS3: Yes ENABLE_FTS3_PARENTHESIS: Yes ENABLE_LOCKING_STYLE=1: Yes ENABLE_RTREE: Yes OMIT_AUTORESET: Yes OMIT_BUILTIN_TEST: Yes OMIT_LOAD_EXTENSION: Yes TEMP_STORE=1: Yes THREADSAFE=2: Yes