2012-09-07 5 views
0

J'ai créé une application de dictionnaire avec base de données SQL, mais le problème est lorsque les utilisateurs recherchent un mot dans UISearchBar le processus de recherche est très lent! pourquoi cela arrive? voici mon code:iOS: recherche lente dans la base de données SQLite

- (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]; 

} 

codes d'affichage de la table:

- (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; 
} 

ÉDITÉ:

-(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]; 
} 
+0

que faites-vous dans la méthode searchWord? – freelancer

+0

@SmartWork vérifier mon article édité – Momi

+0

NSLog votre instruction SELECT pour être sûr que vous obtenez ce que vous attendez. –

Répondre

1

D'abord, le champ que vous êtes à la recherche devrait donc constituer un index, sinon vous régresse dans une recherche linéaire sur tous les enregistrements de la base de données. Deuxièmement, vous ne devriez pas utiliser LIKE de cette manière, car vous allez probablement reculer dans une recherche linéaire. Au lieu de cela, vous devez dé-normaliser vos données afin de pouvoir rechercher plus facilement les sous-chaînes. Vous allez vous retrouver avec une base de données plus grande, mais votre recherche sera beaucoup plus rapide.

Sans informations beaucoup plus détaillées sur votre recherche spécifique, c'est difficile à dire. Enfin, même si nous avions des informations spécifiques, nous ne pouvions en faire autant. La seule façon de déterminer le goulet d'étranglement des performances et de déterminer si les modifications le corrigent réellement, vous devez utiliser des outils de performance (comme Instruments) pour collecter des données et exécuter de nombreux tests pour déterminer exactement ce qui se passe. . Vraiment, les forums comme ceux-ci ne peuvent que faire beaucoup. Les gens peuvent reconnaître des algorithmes terriblement inefficaces, mais nous sommes vraiment terribles pour repérer les problèmes de performance. C'est pourquoi nous avons des outils d'analyse. Apprenez à les utiliser, et votre vie sera beaucoup plus simple.

Bonne chance!

EDIT

Pour répondre aux commentaires: L'utilisation LIKE n'est pas une comparaison de chaînes. C'est, bien, "comme" une comparaison de chaîne :-). Il accepte les caractères génériques et doit faire plus de travail pour la comparaison. C'est assez lent et peut facilement se dégrader en une recherche linéaire. Lorsque vous parlez de dénormalisation, je veux dire prendre le champ Name et le diviser en un champ de recherche qui lui est propre.Retirer l'étui et les marques diacritiques. Peut-être même casser chaque nom en N noms, en fonction de la longueur. Utilisez le champ "consultable" comme une carte pour les éléments de données réelles. Les bases de données sont parfaites pour cela. Ou, en faisant une analyse, vous pouvez probablement déterminer qu'après un certain nombre de caractères (devinez environ 3-4), le nombre de correspondances de préfixe est assez petit pour une recherche efficace. Vous pouvez ensuite faire des permutations sur ceux-ci.

De même, à partir du code édité, il semble que la base de données soit ouverte à chaque fois. Cela peut être un tueur. À part ça, je ne sais pas grand-chose sur l'utilisation de l'API straight-sqlite, donc je ne peux pas commenter cette partie.

+0

Questioner utilise LIKE pour trouver une chaîne commençant par le texte entré. Je suis d'accord qu'un index serait utile, mais je ne vois pas ce que vous voulez dire à propos de la dénormalisation dans ce contexte. – Bryan

+0

Briser les chaînes de ce champ dans un attribut séparé de mots et/ou parties de mots pour une recherche plus efficace. Même les répartir dans une structure de données différente si nécessaire. Un index n'aide pas si votre recherche "saute" des caractères principaux pour trouver des correspondances sur des caractères/mots internes parce que vous devez toujours examiner chaque entrée pour voir si elle correspond. –

+0

Bien, mais la recherche dans cette question particulière/ne saute pas/sauter les caractères principaux. – Bryan

0

la première chose que je ne voudrais pas faire est d'allouer de l'espace à chaque fois quelque chose de changement d'utilisateur dans la barre de recherche .... Init la base de données dans le viewDidLoad méthode ...

Mais je pense qu'il est encore mieux d'enregistrer les informations nécessaires pour UITableView dans un NSDictionary ou quelque chose et de rechercher sur ce tableau/dictionnaire ... Je l'ai fait dans une de mes applications et il fonctionne très bien (la table a plus de 7000 lignes)

Greez Chris

+0

Votre recommandation de stocker toutes les données en mémoire pour la recherche est un compromis entre l'heure de démarrage et le temps de recherche. En outre, vous pouvez avoir plus de données que ce qui peut raisonnablement tenir dans la mémoire. Ce n'est donc pas toujours une bonne idée. – Bryan

0

en outre, vous devriez faire la recherche sur un fil de fond, pour ne pas bloquer l'interface utilisateur. De cette façon, il se sentira beaucoup plus vite pour l'utilisateur.

Voici comment faire: Searching on a Background Thread

0

Votre prédicat LIKE '%word%' n'utilisera pas l'index, LIKE 'word%', cependant.

Je suggère de rendre l'index insensible à la casse (COLLATE NOCASE), ce qui serait attendu d'une recherche de dictionnaire.

Questions connexes