2015-04-01 3 views
0

J'ai une requête qui fonctionne parfaitement bien sur les appareils Gingerbread et Jellybean mais qui tourne beaucoup plus lentement sur les appareils Lollipop. Je suis certain que la requête est correcte et bien écrite car elle fonctionne bien sur les anciens appareils.SQLite Query s'exécute beaucoup plus lentement sur Android Lollipop

Cursor c; 
String query = QUERY STRING; 

c = db.rawQuery(query,new String[]{Integer.toString(a),Integer.toString(b)}); 

Log.e("SQL_QUERY_PROGRESS","1"); 

while(c.moveToNext()){ 
    Log.e("SQL_QUERY_PROGRESS","2"); 
    // Do stuff with data 
} 

c.close(); 

Sur l'appareil Gingerbread il n'y avait que 0,008 d'une seconde entre les deux messages du journal alors que sur les dispositifs de Lollipop il prenait ~ 8 secondes, ce qui est incroyablement lent. Ce que je n'arrive pas à comprendre, c'est que les périphériques Lollipop sont plus récents et ont plus de RAM, de puissance CPU, donc la logique veut que les nouveaux périphériques lancent la requête plus rapidement que les anciens.

Pourrait-il y avoir un bug avec la version de Java utilisée sur Lollipop ou est-ce que la version de SQLite pourrait provoquer cette diminution massive de la vitesse?

Je l'ai utilisé adb shell et navigué dans le fichier de base de données et exécution de la requête en utilisant sqlite3 sur les appareils Lollipop et il a couru presque instantanément ce qui me fait penser qu'il est plus d'un problème de Java que problème SQLite. Je n'ai aucune idée de ce qui pourrait causer le retard, donc toute aide ou idée serait grandement appréciée afin que je puisse enquêter plus loin!

+0

Les périphériques Lollipop ont généralement une partition 'userdata' cryptée - ce qui ralentit de nombreuses opérations liées au stockage, y compris l'accès à la base de données. En outre, un appareil plus récent ne se traduit pas toujours par un stockage plus rapide. Il y a beaucoup de facteurs en jeu. Donc, sauf si vous voulez exécuter votre requête sur le même jeu de données sur le même périphérique juste sous différentes versions android et fournir plus d'informations - votre question est discutable et hors-sujet –

+0

Exécutez-vous la requête dans le thread principal ou est-il en cours d'exécution dans un thread séparé (AsyncTask, Thread, IntentService ...)? – ucsunil

+0

@AlexP. Je l'ai utilisé sur un Nexus 5 et un Galaxy S4 sur Lollipop, sur un Vodafone Smart II sur Gingerbread et sur un Galaxy S2 sur Jellybean, donc ces appareils devraient être au moins aussi rapides, sinon plus rapides en théorie et pas 1000 fois plus lents ! – PriestVallon

Répondre

2

Voici comment j'ai résolu cela.

  1. Vous devez d'abord déterminer quelles requêtes sont problématiques. Je l'ai fait en remplaçant tous les appels rawQuery() avec ma propre méthode. Il consignera l'heure entre chaque requête.
private static Cursor runQuery(String query) { 
    System.out.println("QUERY: " + query); 
    Cursor tmpCursor = DatabaseManager.getInstance().openDatabase().rawQuery(query, null); 
    System.out.println("TIME: " + (System.currentTimeMillis() - Main.time)); 
    Main.time = System.currentTimeMillis(); 
    return tmpCursor; 
} 

Vérifiez le temps dans d'autres parties de votre code que vous soupçonnez. Maintenant, vous verrez entre quelles requêtes l'heure est perdue. C'est en fait la logique du curseur, comme c.moveToFirst() qui sont les plus chères. Mettez une vérification du temps après ceux-ci, aussi pour vérifier.

  1. Lorsque vous avez trouvé la requête, examinez-la et vérifiez quelles colonnes la requête doit parcourir. Dans mon cas, j'ai eu une jointure sur une colonne qui est dans une table avec un grand nombre de lignes. C'est la colonne dont vous avez besoin pour la prochaine étape:
  2. Créer un index pour cette colonne, comme ceci:
    CREATE INDEX idx_bibref ON responses(bibreference);

Vous pouvez exécuter ce dans le terminal pour les tests (sqlite3) ou mieux encore le mettre dans votre onUpgrade méthode. C'est tout. Maintenant toutes les méthodes de curseur s'exécutent rapidement, comme sur les versions précédentes d'Android.


post ancienne:

j'éprouve le même problème. Je l'ai en cours d'exécution dans une tâche asynchrone, donc je peux confirmer que, comme l'a dit PriestVallon, cette exécution sur le thread principal de l'interface utilisateur, bien que pas vraiment efficace, n'est pas la cause du problème. Apparaît uniquement sur Lollipop. Ran cela sur les téléphones et les émulateurs avec 4.4. Pas d'issues. Mon enquête jusqu'à présent a donné que c'est lié à la logique du curseur et non la requête elle-même.Par exemple:

c.moveToFirst(); 
c.moveToNext(); 
c.getCount(); 
etc... 

Habituellement, quand courir après des requêtes plus complexes avec des jointures (mais que je ne peux pas confirmer encore 100%).

Peut-être que cela peut aider.

(. Excusez-moi de mettre cela dans une réponse, par opposition à un commentaire, mais je n'ai pas assez réputation pour commenter)

+0

Moi aussi j'ai eu ce problème. Je serais curieux de savoir quelle est la cause première. – user1179330

2

J'ai eu un problème similaire - une requête SQLite qui a fonctionné très bien avant Lollipop fonctionnait un lot plus lent sur Lollipop. C'était une requête sur 3 tables jointes, et prenait plus de 10 secondes! Après avoir essayé toutes sortes de choses, j'ai trouvé le problème: Lollipop utilise SQLite 3.8, qui utilise un optimiseur de requêtes différent, et pour une raison quelconque, il utilisait un mauvais index dans l'une des jointures. Après avoir obtenu une copie de la base de données de mon périphérique de test, j'ai utilisé l'outil de ligne de commande SQLite avec "expliquer le plan de requête" sur la requête. En comparant la production d'avant 3.8 à postérieurement à 3.8, ce dernier utilisait un index différent et incorrect. D'après ce que j'ai lu, exécuter "ANALYZE" sur la base de données peut l'avoir corrigé, mais comme je n'avais pas vraiment besoin du mauvais index utilisé, j'ai simplement laissé tomber l'index. Maintenant, la requête utilise le bon index, et la requête est à nouveau rapide.