日期:2014-05-16 浏览次数:20446 次
android:利用DatabaseUtils.InsertHelper提高insert速度 insertandroidlockingsqlitedatabaseexception Android OS中的DatabaseUtils.InsertHelper类提供的方法能够提高对sqlite数据库的insert速度 。但是,有关其使用的文档说明或者例子很少。希望这篇文章能有助于帮你揭开其神秘的面纱。 我们经常有在SqliteOpenHelper的onCreate方法里面批量进行insert操作的情况,所以这个例子参照这种情景【已有隐式事务】(批量处理意味着包含了有事务处理,我们知道,使用事务对程序的performance有影响,下面会有介绍) 假设onCreate方法如下: private class DatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { ContentValues values = new ContentValues(); while (moreRowsToInsert) { // ... create the data for this row (not shown) ... // Add the data for each column values.put( "Greek" , greekData); values.put( "Ionic" , ionicData); // ... values.put( "Roman" , romanData); // Insert the row into the database. db.insert( "columnTable" , null , values); } } //... } 使用DatabaseUtils.InsertHelper,则代码如下: import android.database.DatabaseUtils.InsertHelper; //... private class DatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { // Create a single InsertHelper to handle this set of insertions. InsertHelper ih = new InsertHelper(db, "columnTable"); // Get the numeric indexes for each of the columns that we're updating final int greekColumn = ih.getColumnIndex("Greek"); final int ionicColumn = ih.getColumnIndex("Ionic"); //... final int romanColumn = ih.getColumnIndex("Roman"); while (moreRowsToInsert) { // ... Create the data for this row (not shown) ... // Get the InsertHelper ready to insert a single row ih.prepareForInsert(); // Add the data for each column ih.bind(greekColumn, greekData); ih.bind(ionicColumn, ionicData); //... ih.bind(romanColumn, romanData); // Insert the row into the database. ih.execute(); } } //... } 由以上代码可以看出,InsertHelper的使用比SQLiteDatabase.insert稍微复杂一点。最主要的区别是使用InertHelper时, 在使用adding("binding")添加对应列数据之前调用iH.prrepareForInsert()方法,并且需要对应列的index, 这个index值是通过循环里面调用ih.getColumnIndex()而获得。用DatabaseUtils.InsertHelper替换SQLiteDatabase.insert之后的代码,效率提升上大致相当于每秒95行和每秒525行数据插入速度。 实际上InsrtHelper并没有做什么神奇的事情,它只是预编译语句的包装类,并且你自已也可以通过 SQLiteDatabase.compileStatement来实现,很多人应该知道InsertHelper使用起来很容易 其他提高insert速度的方法 除此之外,通过对以下两个方面的优化,可以让插入速度提高到900行每秒,当然,这些技巧的使用是否有效和你的程序也有很大关系 1.不要绑定空列 在我的程序,至少有50%的列是空值。碰到空值列,就不调用ih.bind()方法对它进行绑定,就我的程序而言,当列值为null或者空的字符串是, 有将近30%的性能提升 2.临时关闭sqlitedatabase的同步锁检查功能 我在SQLiteOpenHelper.onCreate的方法中load数据库,在此期间,假如只有一个线程访问databaser,那么就不需要sqlite进行同步访问检查 所以,调用SQLiteDatabase.setLockingEnabled(false) 暂时将锁检查关闭。这个措施可以有35%的速度提升 public void onCreate(SQLiteDatabase db) { //... try { // *Temporarily* (have I emphasized that enough?) disable // thread locking in the database. Be sure to re-enable locking // within a finally block. db.setLockingEnabled(false ); // ... load the database ... } finally { db.setLockingEnabled(true ); } 事务和性能 很多人都知道显式使用事务控制的好处。?? 然而,SQLiteOpenHelper在调用其回调函数(onCreate,onUpgrade,onOpen)之前已经创建了一个事务,因此,在这几个方法里面 没有必要显式声明一个事务控制(SQLiteOpenHelper默认事务已成功提交,除非方法里抛出exception) 如果insert操作不在SQLiteOpenHelper的上述回调方法中,那么你就可以使用显式的事务控制声明,主要使用的API有以下几个: SQLiteDatabase.beginTransaction SQLiteDatabase.setTransactionSuccessful SQLiteDatabase.endTransaction. 可以在里面嵌套事务,不过,很明显它对性能的提升好像没什么帮助。实际上,嵌套事务甚至降低了程序的性能(大约1%,和测量精度有关)。试着周期性的关闭当前事务--先关闭由SQLiteOpenHelper打开的事务-再打开一个新的。同样对性能的提升没有明显的作用,即便有也非常有限。 有些地方把握不准,恐有误导,欢迎斧正 贴上原文:Android: Using DatabaseUtils.InsertHelper for faster insertions into SQLite database