日期:2014-05-16  浏览次数:20367 次

android:利用DatabaseUtils.InsertHelper提高insert速度

?

?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有以下几个: