3

現在、一度に 100 億を超えるデータを Android に挿入する必要があります。ただし、メモリ不足の問題により、プログラムがクラッシュします。sqlite 挿入テストは非常に単純です。forループを使用してSQL挿入コマンドを生成し、「begin」と「commit」でwrqppedするだけです。

    private ArrayList<String> sqlInsertCmd = new ArrayList<String>();
    int QUERIES_TIMES = 10000000;
    private void CreateInsertQueries()
    {
        Random localRandom = new Random();
        int i = 0;
        while (i < QUERIES_TIMES)
        {
            int j = localRandom.nextInt(100000);
            sqlInsertCmd.add("insert into " + TABLE + " (a,b,c) values (" + i + "," + 
            j + ",'" + String.valueOf(j) + "')");
            ++i;
        }
    }

    Then..

    mDB.beginTransaction();
    for (int i=0; i<this.QUERIES_TIMES; i++)
    {
        mDB.execSQL(sqlInsertCmd.get(i));
    }
    mDB.setTransactionSuccessful();
    mDB.endTransaction();

メモリ不足を回避するためのアイデアはありますか?

ありがとうございます。上記のコードは単なる例です。私のプログラムでは、もっと複雑です。コンテナー (hashMap など) に何かを格納し、SQL ステートメントを動的に構築する必要があります。10 個のサービスを作成し、各サービスが 1/10 のジョブを処理することはできますか?

4

2 に答える 2

3

いくつかのこと:

  1. 一括挿入を行う際の一般的なヒントについては、こちらの回答を参照してください。
  2. INSERT ステートメント (この場合は ArrayList<>) 用の一時コンテナーを用意する必要はありません。try...finally でbeginTransaction()endTransaction()を使用するだけです。
  3. 例のように、各 INSERT ステートメントを構築するのに対して、 SQLiteStatementを介してプリコンパイル済みステートメントを利用します。これは不必要なスラッシングです。

手っ取り早い例:

// note: untested code used for illustration!
private boolean bulkInsertData(SQLiteDatabase db, final String tableName) {
    final int NUM_ROWS = 10000000;

    Random random = new Random();

    try {
        SQLiteStatement insStmt = insStmt = db.compileStatement("INSERT INTO " + tableName + " (a, b, c) VALUES (?, ?, ?);");
        db.beginTransaction();
        try {
            for(int i = 0; i < NUM_ROWS; i++) {
                insStmt.bindLong(1, i);
                insStmt.bindLong(2, random.nextInt(100000));
                insStmt.bindString(3, String.valueOf(i));
                insStmt.executeInsert();    //  should really check value here!
            }
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();    
        }
    } catch(SQLException se) {
        return false;
    }

    return true;
}
于 2012-05-16T21:32:49.983 に答える
0

10000000 個の SQL クエリを含む ArrayList を作成する代わりに (これが OutOfMemory の潜在的な理由になる可能性があります)、クエリ文字列を作成している同じループでレコードの挿入を開始するだけです。例えば:

private void CreateInsertQueries(SQLiteDatabase mDB)
{
    Random localRandom = new Random();
    int i = 0;
    String query;

    try{
        mDB.beginTransaction();

        while (i < QUERIES_TIMES)
        {
            int j = localRandom.nextInt(100000);
            query = "insert into " + TABLE + " (a,b,c) values (" + i + "," + 
            j + ",'" + String.valueOf(j) + "')";
            ++i;

            mDB.execSQL(query);
        }

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

そうすることで、非常に多くのレコードを保持しているために OutOfMemory の理由である ArrayList をスキップするのに役立ちます (私はそう思います)。

また、外部メモリを使用してデータベース ファイルをホストしていることを確認してください。そうしないと、すべての電話機がより大きな内部メモリを持っているわけではありません。

于 2012-05-16T11:59:59.593 に答える