web-dev-qa-db-fra.com

Insertion en masse sur Android

Je souhaite insérer en masse environ 700 enregistrements dans la base de données Android lors de ma prochaine mise à niveau. Quelle est la façon la plus efficace de le faire? De divers articles, je sais que si j'utilise Insert instructions, je devrais les envelopper dans une transaction. Il y a aussi un post sur l'utilisation de votre propre base de données, mais j'ai besoin de ces données pour aller dans la norme de mon application Android Notez que cela ne serait effectué qu'une seule fois par appareil.

Quelques idées:

  1. Mettez un tas d'instructions SQL dans un fichier, lisez-les en ligne à la fois et exécutez le SQL.

  2. Mettez les données dans un fichier CSV, ou JSON, ou YAML, ou XML, ou autre. Lisez une ligne à la fois et faites db.insert().

  3. Découvrez comment effectuer une importation et effectuer une seule importation de l'ensemble du fichier.

  4. Créez une base de données sqlite contenant tous les enregistrements, copiez-la sur le périphérique Android, et fusionnez en quelque sorte les deux bases de données.

  5. [EDIT] Mettez toutes les instructions SQL dans un seul fichier dans res/values ​​comme une grande chaîne. Lisez-les ensuite une ligne à la fois et exécutez le SQL.

Quelle est la meilleure façon? Existe-t-il d'autres moyens de charger des données? 3 et 4 sont-ils même possibles?

49
Ron Romero

Normalement, chaque fois que db.insert() est utilisé, SQLite crée une transaction (et le fichier journal résultant dans le système de fichiers), ce qui ralentit les choses.

Si vous utilisez db.beginTransaction() et db.endTransaction() SQLite crée un seul fichier journal sur le système de fichiers, puis valide toutes les insertions en même temps, accélérant considérablement les choses.

Voici un pseudo-code de: insertion par lots dans la base de données SQLite sur Android

try
{
  db.beginTransaction();

  for each record in the list
  {
    do_some_processing();

    if (line represent a valid entry)
    {
      db.insert(SOME_TABLE, null, SOME_VALUE);
    }

    some_other_processing();
  }

  db.setTransactionSuccessful();
}
catch (SQLException e) {}
finally
{
  db.endTransaction();
}

Si vous souhaitez abandonner une transaction en raison d'une erreur inattendue ou de quelque chose, simplement db.endTransaction() sans d'abord définir la transaction comme réussie (db.setTransactionSuccessful()).

Une autre méthode utile consiste à utiliser db.inTransaction() (renvoie true ou false) pour déterminer si vous êtes actuellement au milieu d'une transaction.

Documentation ici

97
Jake Wilson

J'ai trouvé que pour les insertions en masse, la classe (apparemment peu utilisée) DatabaseUtils.InsertHelper est plusieurs fois plus rapide que l'utilisation de SQLiteDatabase.insert.

Deux autres optimisations ont également contribué aux performances de mon application, bien qu'elles ne soient pas toujours appropriées:

  • Ne pas bind les valeurs vides ou null.
  • Si vous pouvez être certain qu'il est sûr de le faire, la désactivation temporaire du verrouillage interne de la base de données peut également améliorer les performances.

J'ai un article de blog avec plus de détails.

34
Dan Breslau

Eh bien, ma solution pour cela est assez étrange mais fonctionne bien ... Je compile une grande somme de données et je l'insère en une seule fois (insertion en bloc?)

J'utilise la commande db.execSQL(Query) et je construis la "requête" avec l'instruction suivante ...

INSERT INTO yourtable SELECT * FROM (
    SELECT 'data1','data2'.... UNION
    SELECT 'data1','data2'.... UNION
    SELECT 'data1','data2'.... UNION
    .
    .
    .
    SELECT 'data1','data2'....
)

Le seul problème est la construction de la requête qui peut être un peu compliquée. J'espère que ça aide

9
Andrew Prat

Cet exemple ci-dessous fonctionnera parfaitement

 String sql = "INSERT INTO " + DatabaseHelper.TABLE_PRODUCT_LIST
                + " VALUES (?,?,?,?,?,?,?,?,?);";

        SQLiteDatabase db = this.getWritableDatabase();
        SQLiteStatement statement = db.compileStatement(sql);
        db.beginTransaction();
        for(int idx=0; idx < Produc_List.size(); idx++) {
            statement.clearBindings();
            statement.bindLong(1, Produc_List.get(idx).getProduct_id());
            statement.bindLong(2,  Produc_List.get(idx).getCategory_id());
            statement.bindString(3, Produc_List.get(idx).getName());
//            statement.bindString(4, Produc_List.get(idx).getBrand());
            statement.bindString(5, Produc_List.get(idx).getPrice());
            //statement.bindString(6, Produc_List.get(idx).getDiscPrice());
            statement.bindString(7, Produc_List.get(idx).getImage());
            statement.bindLong(8, Produc_List.get(idx).getLanguage_id());
            statement.bindLong(9, Produc_List.get(idx).getPl_rank());
            statement.execute();

        }
        db.setTransactionSuccessful();
        db.endTransaction();
9
arun-r