0

SQL データベースを使用して辞書アプリを作成しましたが、ユーザーが単語を検索するときにUISearchBar検索プロセスが非常に遅いという問題があります。なぜこれが起こるのですか?ここに私のコードがあります:

- (void)updateSearchString:(NSString*)aSearchString
{
    [self.myTable reloadData];
}

- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {

    searchbar.showsCancelButton = YES;

    if([searchText length] > 0) {

        dbClass=[[DB alloc]init];
        [dbClass searchWord:searchText];

    }else
    {
        dbClass=[[DB alloc]init];
        [dbClass searchWord:@""];
    }

    [self.myTable reloadData];

}

テーブル ビュー コード:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    appClass = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSLog(@"%d",appClass.wordList.count);
    return  appClass.wordList.count;

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    appClass = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    readerClass = (Reader *)[appClass.wordList objectAtIndex:indexPath.row];

    cell.textLabel.text  = readerClass.Name;


    return cell;
}

編集済み:

    -(void)searchWord:(NSString *)txt{

    NSMutableArray *DB_Array = [[NSMutableArray alloc] init];


    NSString *dbPath=[self getDBPath];

    if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {

        NSString *sql =[NSString stringWithFormat:@"SELECT * FROM DIC Where Name LIKE \'%@%%\' ",txt];

        //        NSLog(@"%@",sql);

        sqlite3_stmt *compiledStatement;

        if(sqlite3_prepare_v2(database, [sql UTF8String] , -1, &compiledStatement, NULL) == SQLITE_OK) {
            while(sqlite3_step(compiledStatement) == SQLITE_ROW) {

                NSInteger oid = sqlite3_column_int(compiledStatement, 0);

                const char* f1 = (const char*)sqlite3_column_text(compiledStatement, 1);
                NSString *oName = f1 == NULL ? nil : [[NSString alloc] initWithUTF8String:f1];

                const char* f2 = (const char*)sqlite3_column_text(compiledStatement, 2);
                NSString *oMean = f2 == NULL ? nil : [[NSString alloc] initWithUTF8String:f2];


                const char* f3 = (const char*)sqlite3_column_text(compiledStatement, 3);
                NSString *oPron = f3 == NULL ? nil : [[NSString alloc] initWithUTF8String:f3];

                NSInteger bm = sqlite3_column_int(compiledStatement, 5);

                readerClass = [[Reader alloc]initWithReadDB:oid Name:oName Mean:oMean Pron:oPron bookMark:bm];

                [DB_Array addObject:readerClass];

            }
        }
        else {
            NSLog(@"Error retrieving data from database.");
        }
        sqlite3_close(database);
    }
    else {

        NSLog(@"Error: Can't open database!");
        NSLog(@" DB Name %@",viewController.dbName);
    }

    AppDelegate *appDelegateClass = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegateClass.wordList removeAllObjects];
    [appDelegateClass.wordList=DB_Array mutableCopy];
}
4

4 に答える 4

1

まず、検索対象のフィールドはインデックスである必要があります。そうしないと、データベース内のすべてのレコードに対する線形検索に回帰します。

第二に、線形検索に回帰する可能性が高いため、そのような方法で LIKE を使用しないでください。代わりに、部分文字列をより簡単に検索できるように、データを非正規化する必要があります。最終的にはより大きなデータベースになりますが、検索ははるかに高速になります。

特定の検索に関するより詳細な情報がなければ、それを判断するのは困難です。

最後に、具体的な情報があったとしても、できることは限られています。

パフォーマンスのボトルネックがどこにあるかを判断し、変更によって実際にそれが解決されるかどうかを判断する唯一の方法は、パフォーマンス ツール (Instruments など) を使用してデータを収集し、多くのテストを実行して何が起こっているかを正確に判断することです。

実際、このようなフォーラムでできることは限られています。人々は恐ろしく非効率なアルゴリズムを認識することができますが、私たちはパフォーマンスの問題を見つけるのが本当に苦手です. そのため、分析ツールがあります。それらを使用することを学ぶと、あなたの人生ははるかに簡単になります.

幸運を!

編集

コメントに対処するには: UsingLIKEは文字列比較ではありません。それは、まあ、文字列比較の「ように」です:-)。ワイルドカードを受け入れ、比較のためにさらに多くの作業を行う必要があります。これは非常に遅く、簡単に線形検索に陥る可能性があります。

非正規化について話すときは、フィールドを取得Nameして、それを独自の検索可能なフィールドに分割することを意味します。大文字と小文字の区別記号を削除します。長さに基づいて、各名前を N 個の名前に分割することもできます。「検索可能」フィールドを実際のデータ項目へのマップとして使用します。データベースはこれに最適です。

または、何らかの分析を行うことで、ある程度の数の文字 (3 ~ 4 程度と推測) の後では、効率的な検索に十分な数のプレフィックス マッチが少ないと判断できる可能性があります。その後、それらの順列を作成できます。

また、編集されたコードから、データベースが毎回開かれているように見えます。 それは殺人者になる可能性があります。 それ以外は、straight-sqlite API の使用についてはよく知らないので、その部分についてコメントすることはできません。

于 2012-09-07T13:32:08.680 に答える
0

述語LIKE '%word%'はインデックスを使用しませんが、使用しますLIKE 'word%'

索引を大文字と小文字を区別しない ( COLLATE NOCASE) にすることをお勧めします。これは、辞書検索から予想されることです。

于 2012-09-09T18:13:53.800 に答える
0

私が最初にしないことは、ユーザーが検索バーで何かを変更するたびにスペースを割り当てることです.... viewDidLoadメソッドでデータベースを初期化します...

しかし、UITableView に必要な情報を NSDictionary などに保存し、この配列/辞書を検索する方が良いと思います...アプリの 1 つでこれを実行しましたが、非常にうまく動作します (テーブルには 7000 行以上あります) )

グリーズ・クリス

于 2012-09-07T12:44:11.853 に答える
0

また、UI がロックされないように、バックグラウンド スレッドで検索を行う必要があります。そうすれば、ユーザーははるかに高速に感じるでしょう。

これを行う方法は次のとおりです。 バックグラウンド スレッドでの検索

于 2012-09-07T12:49:59.027 に答える