SQLiteで挿入を高速化する方法

良い一日。 私の最初のAndroidアプリケーションでは、データベースを操作する必要にすぐに直面しました。 ユーザーに初期データセット(約5000〜6000レコード)を提供する必要がありました。これを使用して、すぐに作業を進めることができました。 JSON形式のデータを含むテキストファイルをアプリケーションに添付し、最初の起動時にそれらを解析してデータベースに格納することが決定されました。 これを間違って行う方法と、後でリファクタリングした後にパフォーマンスを向上させる方法について詳しく読むことができます。



最初のJavaアプリケーションを書いた人が、Androidのすぐ下でさえ、何をいじらなければならなかったかについて、長い話をしたくありません。 私の意見では、あなたを物語で退屈させるのではなく、すぐにビジネスに取り掛かる方が良いと思います。 結局のところ、ここで見たのは答えだったのですか?



そうだった。 単純に、DBHelperはシングルトンを介して実装され、データベースオブジェクトは同じ方法で保存されました。

public class DBHelper extends SQLiteOpenHelper { ... private static DBHelper instance; private static SQLiteDatabase db; public static DBHelper getInstance() { if (instance == null) instance = new DBHelper(Pleazzme.getAppContext()); return instance; } public static SQLiteDatabase getDB() { if (db == null) db = getInstance().getWritableDatabase(); return db; } ... }
      
      





別のAsyncTaskでパーサーが起動され、ループ内でsave()メソッドを使用してオブジェクトが提供されました。

 ... public void save() { ContentValues values = new ContentValues(); values.put(id, Id); values.put(name, Name); values.put(categoriesIds, App.gson.toJson(CategoriesIds)); values.put(datecreated, DateCreated.getTime()); Document.save(); values.put(document_id, Document.getId()); values.put(hasbarcode, hasBarcode); values.put(headofficeaddress, HeadOfficeAddress); values.put(phonenumbers, PhoneNumbers); values.put(website, WebSite); values.put(popularity, Popularity); values.put(keywords, Keywords); DBHelper.getDB().insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE); } ...
      
      







この状況では、オブジェクトをデータベースに40〜50ミリ秒保存しました。 その結果、少なくとも4分間、すべての保存が私に注がれました。 当然、これはユーザーには適していませんでした。 そして、挿入を高速化するソリューションのために検索エンジンとインターネットを喫煙し始めました。 答えはここドキュメントにありました。



プロセスを高速化するために、次の手順が実行されました。





コードがより雄弁であることを考えると、最終的にデザインは次のようになります。

 public class DBHelper extends SQLiteOpenHelper { ... private static DBHelper instance; private static SQLiteDatabase db; public static DBHelper getInstance() { if (instance == null) instance = new DBHelper(Pleazzme.getAppContext()); return instance; } public static SQLiteDatabase getDB() { if (db == null) db = getInstance().getWritableDatabase(); return db; } ... /*new code*/ public static void bigDataBegin(SQLiteDatabase _db){ //_db.setLockingEnabled(false); //_db.execSQL("PRAGMA synchronous=0"); _db.beginTransaction(); } public static void bigDataEnd(SQLiteDatabase _db){ //_db.setLockingEnabled(true); //_db.execSQL("PRAGMA synchronous=1"); _db.setTransactionSuccessful(); _db.endTransaction(); } }
      
      







保存されたオブジェクトクラス:

 ... private static InsertHelper ih; public void save(final SQLiteDatabase db) { if(ih == null) ih = new InsertHelper(db, table); ih.prepareForInsert(); try { ih.bind(ih.getColumnIndex(key), value); } catch (NullPointerException e) { } ..... ih.execute(); ih.close(); } ...
      
      







そして、これらすべてがオブジェクトを保存するためのコードを「離陸」します。

 SQLiteDatabase database = DBHelper.getDB(); DBHelper.bigDataBegin(database); for (int i = 0; i < currSize; i++) { gson.fromJson(o, Data.class).save(database); } DBHelper.bigDataEnd(database);
      
      







すべての操作と速度の測定の後、結果は次のようになりました。





この情報が誰かに役立つことを願っています。 まず第一に、初心者プログラマー向けに設計されています。 誰かがより効果的なオプションを提供できるなら、私は嬉しいだけです。



UPD。

意識のない喜びの爆発の中で、私は発見を共有しました。 テスト後、別のパラレルスレッドでデータを追加しようとすると、ayahが追加され、さらに一部のデバイスはプラグマを直接使用しようとすることを誓うことが判明しました。



したがって、1つのトランザクションの使用のみが残ります(エラーコードをコメント化しました)。 この形式では、可能な限り安全なままです。 確かに、同時に、ドキュメントよりも多くの情報を運ぶものに対するすべての主張を失います。



私にとって別の興味深い事実は、弟(HTC Wildfire)が顕著な増加を示さなかったにもかかわらず、パワフルなデバイス(たとえば、4.0.4搭載のSGS2)で顕著なパフォーマンスの向上が観察されたことです...



All Articles