1

iPhone アプリでは SQLite データベースを使用しており、そのためにfmdbに依存しています。iOS 5 を搭載した iPhone では、最初の DB アクセスに最大で 10 秒かかりますが、iOS 6 では 30 秒から 2 分 40 秒かかります (これは iPhone 4 および 4S では、iPhone 5 では約 15 から 20 秒かかります)。私が気づいたことの 1 つは、時間が常に一貫していることです。1 つの電話で 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;
}

DBを開く

+ (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] 命令、より具体的にrc = sqlite3_step([_statement statement]);は FMDB next コード内にあります。したがって、問題は実際には SELECT ステートメントにあると思います。

更新 2:

SQL ステートメントを単純化しようとしましたが、 [FMResultSet next] SELECT Levada_id FROM Levada Always clean your projectでまだ時間がかかりすぎます。

4

1 に答える 1

2

FMDB コードを詳細に調べてみたところ、この種の遅延の原因となるものは何もありません。FMDB は非常に薄いラッパーであり、ほぼ確実にその動作に責任を負いません。そこには十分な数の SQLite/FMDB ユーザーもいます。実際に iOS 6 に SQLite/FMDB 関連の問題があるとしたら、私は非常に驚かれることでしょう。

しかし、あなたの SELECT ステートメントをちらりと見ると、それはかなり複雑に見えます。私がお金を賭けたとしたら、問題が実際にデータベースに関連している場合、それが遅延の原因であるに違いありません。これは、コードを 1 ステップ実行すれば簡単に確認できます。または、前後に NSLog ステートメントを挿入すると、タイムスタンプ付きのログ ステートメントが得られ、問題が明らかになります。

要するに、問題が実際にデータベースに関連していると仮定すると、ほぼ確実に SQLite の問題です。呼び出しを使用してすべてを行うようにこの関数を書き直すsqlite3_xxx()と、同じパフォーマンスの問題が発生する可能性があります。そうは言っても、iOS6 への移行に伴う FMDB/SQLite のパフォーマンスの問題は見られませんでした。また、iOS 6 の SQLite/FMDB で広範囲にわたるパフォーマンスの問題が発生した場合、血が凍るような遠吠えが聞こえるだろうと思っていたでしょう。

その sql ステートメントを SQLite のEXPLAINに通してからテーブルを最適化し、適切なインデックスがあることを確認するか、そうでなければ SQL を再構築することに焦点を当てます。コンピューターの SQLite でデータベースを開き、そこでクエリを分析してみてください。

iOS 6 と iOS 5 でこの種のパフォーマンスの問題が発生する原因については、私はデータベースを開く方法の変更についてよく知りません。

プロファイリングで SQLite の問題が確認されたのか、それとも SQLite/FMDB とはまったく関係のない問題なのかを聞くのは非常に興味深いことです。


アップデート:

iOS 5.1.1 と 6.0.1 の SQLite 構成の間に興味深い構成変更があるかどうかを確認することにしましたが、何も思い浮かびません。(異なるスレッド モデルは確実にパフォーマンスに影響を与える可能性がありますが、見た目は同じです。) iOS 6 は確かに少し新しいバージョンの SQLite を使用していますが、それが悪影響を与えるとは思えません。

デバイス: iPhone OS
iOS: 5.1.1
SQLite 構成:
  バージョン: 3.7.7
  スレッドセーフ: はい
  オプション:
    ENABLE_FTS3: はい
    ENABLE_FTS3_PARENTHESIS: はい
    ENABLE_LOCKING_STYLE=1: はい
    ENABLE_RTREE: はい
    OMIT_AUTORESET: はい
    OMIT_BUILTIN_TEST: はい
    OMIT_LOAD_EXTENSION: はい
    TEMP_STORE=1: はい
    THREADSAFE=2: はい
デバイス: iPhone OS
iOS: 6.0.1
SQLite 構成:
  バージョン: 3.7.13
  スレッドセーフ: はい
  オプション:
    カーディール: はい
    ENABLE_FTS3: はい
    ENABLE_FTS3_PARENTHESIS: はい
    ENABLE_LOCKING_STYLE=1: はい
    ENABLE_RTREE: はい
    OMIT_AUTORESET: はい
    OMIT_BUILTIN_TEST: はい
    OMIT_LOAD_EXTENSION: はい
    TEMP_STORE=1: はい
    THREADSAFE=2: はい
于 2012-12-04T22:14:13.457 に答える