Android SQLite数据库:插入缓慢

ben*_*nvd 91 database sqlite performance android insert

我需要解析一个相当大的XML文件(大约在一百千字节和几百千字节之间变化),我正在使用它Xml#parse(String, ContentHandler).我目前正在使用152KB文件进行测试.

在解析期间,我还使用类似于以下的调用将数据插入SQLite数据库中:getWritableDatabase().insert(TABLE_NAME, "_id", values).对于152KB的测试文件(大约插入200行),所有这一切大约需要80秒.

当我注释掉所有插入语句(但留下其他所有内容,例如创建ContentValues等)时,同一个文件只需要23秒.

数据库操作有这么大的开销是正常的吗?我可以做点什么吗?

War*_*ith 189

你应该进行批量插入.

伪代码:

db.beginTransaction();
for (entry : listOfEntries) {
    db.insert(entry);
}
db.setTransactionSuccessful();
db.endTransaction();
Run Code Online (Sandbox Code Playgroud)

这极大地提高了我的应用程序中的插入速度.

更新:
@Yuku提供了一篇非常有趣的博文:Android使用inserthelper更快地插入到sqlite数据库中

  • 以这种方式插入所有ContentValues只需要一两秒钟.非常感谢! (4认同)
  • 用事务包装我的60个插件会使性能提高10倍.用事务包装它并使用预准备语句(SQLiteStatement)将其增加20倍! (2认同)
  • benvd感谢您的评论.我插入了20k记录,花了大约8分钟,但在使用交易后只花了20秒:-) (2认同)
  • 此博客条目使用几乎隐藏InsertHelper http://www.outofwhatbox.com/blog/2010/12/android-using-databaseutils-inserthelper-for-faster-insertions-into-sqlite-database/讨论了另一种优化 (2认同)

qef*_*zec 68

由于Yuku和Brett提到的InsertHelper 现在已被弃用(API级别17),因此Google推荐的正确选择似乎是使用SQLiteStatement.

我使用了这样的数据库插入方法:

database.insert(table, null, values);
Run Code Online (Sandbox Code Playgroud)

在我遇到一些严重的性能问题之后,以下代码将我的500次插入从14.5秒加速到仅270毫秒,太棒了!

以下是我使用SQLiteStatement的方法:

private void insertTestData() {
    String sql = "insert into producttable (name, description, price, stock_available) values (?, ?, ?, ?);";

    dbHandler.getWritableDatabase();
    database.beginTransaction();
    SQLiteStatement stmt = database.compileStatement(sql);

    for (int i = 0; i < NUMBER_OF_ROWS; i++) {
        //generate some values

        stmt.bindString(1, randomName);
        stmt.bindString(2, randomDescription);
        stmt.bindDouble(3, randomPrice);
        stmt.bindLong(4, randomNumber);

        long entryID = stmt.executeInsert();
        stmt.clearBindings();
    }

    database.setTransactionSuccessful();
    database.endTransaction();

    dbHandler.close();
}
Run Code Online (Sandbox Code Playgroud)

  • 这里要避免一个问题:bindString中的索引是基于1而不是基于0 (14认同)

Bre*_*ett 13

编译sql insert语句有助于加快速度.它还需要更多的努力来支撑一切并防止可能的注射,因为它现在都在你的肩上.

另一种可以加快速度的方法是文档不足的android.database.DatabaseUtils.InsertHelper类.我的理解是它实际上包装了编译的insert语句.对于我的大型(200K +条目)但简单的SQLite插入,从非编译的事务处理插入到编译的事务插入,速度增加了3倍(每个插入2ms到每插入0.6ms).

示例代码:

SQLiteDatabse db = getWriteableDatabase();

//use the db you would normally use for db.insert, and the "table_name"
//is the same one you would use in db.insert()
InsertHelper iHelp = new InsertHelper(db, "table_name");

//Get the indices you need to bind data to
//Similar to Cursor.getColumnIndex("col_name");                 
int first_index = iHelp.getColumnIndex("first");
int last_index = iHelp.getColumnIndex("last");

try
{
   db.beginTransaction();
   for(int i=0 ; i<num_things ; ++i)
   {
       //need to tell the helper you are inserting (rather than replacing)
       iHelp.prepareForInsert();

       //do the equivalent of ContentValues.put("field","value") here
       iHelp.bind(first_index, thing_1);
       iHelp.bind(last_index, thing_2);

       //the db.insert() equilvalent
       iHelp.execute();
   }
   db.setTransactionSuccessful();
}
finally
{
    db.endTransaction();
}
db.close();
Run Code Online (Sandbox Code Playgroud)