3

目前,我必须一次将超过 100 亿的数据插入到我的 android 中。但是,内存不足的问题会使程序崩溃。sqlite 插入测试非常简单。只需使用 for 循环生成 sql insert 命令并由“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. 通过SQLiteStatement使用预编译语句与构建每个 INSERT 语句,如您的示例中所示。这是不必要的折腾。

快速而肮脏的例子:

// 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 查询(可能是 OutOfMemory 的潜在原因)的 ArrayList,不如简单地在创建查询字符串的同一循环中开始插入记录。例如:

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

这样做将帮助您跳过 ArrayList,这(我认为)是 OutOfMemory 的原因,因为它保存了这么多记录。

并确保您确实使用外部存储器来托管您的数据库文件,否则并非所有手机都有更大的内部存储器。

于 2012-05-16T11:59:59.593 回答