web-dev-qa-db-ja.com

Androidデバイスでの一括挿入

次のアップグレードでAndroidデータベースに約700レコードを一括挿入します。これを行う最も効率的な方法は何ですか?さまざまな投稿から、Insertを使用すると post 独自のデータベースの使用についてもありますが、アプリの標準Androidデータベースに移動するにはこのデータが必要です。これは、デバイスごとに1回だけ実行されることに注意してください。

いくつかのアイデア:

  1. SQLステートメントの束をファイルに入れ、一度に1行ずつ読み取り、SQLを実行します。

  2. データをCSVファイル、JSON、YAML、またはXMLなどに入れます。一度に1行ずつ読み取り、db.insert()を実行します。

  3. インポートの方法と、ファイル全体の単一インポートの方法を見つけます。

  4. すべてのレコードを含むsqliteデータベースを作成し、それをAndroidデバイスにコピーし、何らかの方法で2つのデータベースをマージします。

  5. [編集]すべてのSQLステートメントをres/valuesの1つのファイルに1つの大きな文字列として入れます。次に、一度に1行ずつ読み取り、SQLを実行します。

最善の方法は何ですか?データをロードする他の方法はありますか? 3と4も可能ですか?

49
Ron Romero

リストの#3または#4を達成するための実行可能な方法があるとは思わない。

他のソリューションのうち、データファイルにダイレクトSQLが含まれる2つと、SQL以外の形式のデータが含まれる2つをリストします。

3つとも問題なく動作しますが、フォーマットされたファイルからデータを取得し、SQLを自分で作成するという後者の提案が最もきれいに見えます。後日、真のバッチ更新機能が追加された場合、データファイルは引き続き使用可能であるか、少なくとも簡単に使用可能な形式に処理できます。また、データファイルの作成はより簡単で、エラーが発生しにくくなります。最後に、「生の」データがあると、他のデータストア形式へのインポートが可能になります。

いずれの場合でも、(前述したように)挿入のグループをトランザクションにラップして、行ごとのトランザクションジャーナルの作成を回避する必要があります。

8
codelark

通常、db.insert()が使用されるたびに、SQLiteはトランザクション(およびファイルシステム内の結果のジャーナルファイル)を作成します。

db.beginTransaction()およびdb.endTransaction()を使用すると、SQLiteはファイルシステム上に単一のジャーナルファイルのみを作成し、すべての挿入を同時にコミットするため、物事が劇的にスピードアップします。

以下にいくつかの擬似コードを示します。 Android上のSQLiteデータベースへのバッチ挿入

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

予期しないエラーまたは何かが原因でトランザクションを中止したい場合は、最初にトランザクションを成功として設定せずに、単にdb.endTransaction()します(db.setTransactionSuccessful())。

別の便利な方法は、db.inTransaction()trueまたはfalseを返す)を使用して、現在トランザクションの途中にいるかどうかを判断することです。

ドキュメントはこちら

97
Jake Wilson

一括挿入の場合、(明らかにほとんど使用されない) DatabaseUtils.InsertHelper クラスは、SQLiteDatabase.insertを使用するよりも数倍高速であることがわかりました。

他の2つの最適化もアプリのパフォーマンスに役立ちましたが、すべての場合に適切とは限りません。

  • 空またはbindnull値を使用しないでください。
  • 安全だとcertainできる場合は、データベースの内部ロックを一時的にオフにすることもパフォーマンス向上に役立ちます。

ブログ投稿 に詳細があります。

34
Dan Breslau

まあ、これに対する私のソリューションは奇妙ですが、うまく機能します...大量のデータをコンパイルして一度に挿入します(一括挿入?)

db.execSQL(Query)コマンドを使用し、次のステートメントで「クエリ」を作成します...

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

唯一の問題は、クエリを構築することです。私はそれが役立つことを願っています

9
Andrew Prat

以下のこの例は完全に機能します

 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