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:
Mettez un tas d'instructions SQL dans un fichier, lisez-les en ligne à la fois et exécutez le SQL.
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()
.
Découvrez comment effectuer une importation et effectuer une seule importation de l'ensemble du fichier.
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.
[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?
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.
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:
bind
les valeurs vides ou null
.J'ai un article de blog avec plus de détails.
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
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();