使用applyBatch插入数千个联系人条目的速度很慢

And*_*ers 35 android android-contentresolver android-contentprovider

我正在开发一个应用程序,我需要插入大量的联系人条目.目前约有600个联系人,共有6000个电话号码.最大的联系人有1800个电话号码.

截至今天的状态是我创建了一个自定义帐户来保存联系人,因此用户可以选择在"联系人"视图中查看联系人.

但插入触点非常缓慢.我使用ContentResolver.applyBatch插入联系人.我尝试了不同大小的ContentProviderOperation列表(100,200,400),但总运行时间约为.相同.插入所有联系人和号码大约需要30分钟!

我发现在SQlite中缓慢插入的大多数问题都会导致交易.但是因为我使用ContentResolver.applyBatch方法,所以我不控制它,我会假设ContentResolver为我负责事务管理.

所以,我的问题是:我做错了什么,或者我能做些什么来加快这个速度?

安德斯

编辑: @jcwenger:哦,我明白了.很好的解释!

那么我将首先插入raw_contacts表,然后插入带有名称和数字的数据表.我将失去的是对我在applyBatch中使用的raw_id的后向引用.

所以我必须获取新插入的raw_contacts行的所有id作为数据表中的外键吗?

jcw*_*ger 51

ContentResolver.bulkInsert (Uri url, ContentValues[] values)而不是ApplyBatch()

ApplyBatch(1)使用事务和(2)它为整个批处理锁定ContentProvider一次,而不是每次操作锁定/解锁一次.因此,它比一次一个(非批量)快一点.

但是,由于批处理中的每个操作都可以具有不同的URI等,因此会产生大量的开销."哦,一个新的操作!我想知道它进入了什么桌子......在这里,我将插入一行......哦,一个新的操作!我想知道它在哪个表格......"无限广告.由于将URI转换为表格的大部分工作涉及大量的字符串比较,因此它显然非常慢.

相比之下,bulkInsert将整堆值应用于同一个表.它说,"批量插入......找到桌子,好吧,插入!插入!插入!插入!插入!" 快多了.

当然,它需要您的ContentResolver有效地实现bulkInsert.大多数人都这样做,除非你自己写的,在这种情况下需要一些编码.

  • 你能指出applyBatch()的确切交易在哪里开始吗?默认的`applyBatch()`方法[只是调用](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.0_r1/android/content/ContentProvider .java#ContentProvider.applyBatch%28java.util.ArrayList%29)适用于传递的ContentProviderOperations,后者只调用内容提供程序中的插入/更新/删除操作. (3认同)

Vir*_*ren 10

bulkInsert:对于那些感兴趣的人,这是我能够试验的代码.注意我们如何避免int/long/floats的一些分配:)这可以节省更多时间.

private int doBulkInsertOptimised(Uri uri, ContentValues values[]) {
    long startTime = System.currentTimeMillis();
    long endTime = 0;
    //TimingInfo timingInfo = new TimingInfo(startTime);

    SQLiteDatabase db = mOpenHelper.getWritableDatabase();

    DatabaseUtils.InsertHelper inserter =
        new DatabaseUtils.InsertHelper(db, Tables.GUYS); 

    // Get the numeric indexes for each of the columns that we're updating
    final int guiStrColumn = inserter.getColumnIndex(Guys.STRINGCOLUMNTYPE);
    final int guyDoubleColumn = inserter.getColumnIndex(Guys.DOUBLECOLUMNTYPE);
//...
    final int guyIntColumn = inserter.getColumnIndex(Guys.INTEGERCOLUMUNTYPE);

    db.beginTransaction();
    int numInserted = 0;
    try {
        int len = values.length;
        for (int i = 0; i < len; i++) {
            inserter.prepareForInsert();

            String guyID = (String)(values[i].get(Guys.GUY_ID)); 
            inserter.bind(guiStrColumn, guyID);


            // convert to double ourselves to save an allocation.
            double d = ((Number)(values[i].get(Guys.DOUBLECOLUMNTYPE))).doubleValue();
            inserter.bind(guyDoubleColumn, lat);


            // getting the raw Object and converting it int ourselves saves
            // an allocation (the alternative is ContentValues.getAsInt, which
            // returns a Integer object)

            int status = ((Number) values[i].get(Guys.INTEGERCOLUMUNTYPE)).intValue();
            inserter.bind(guyIntColumn, status);

            inserter.execute();
        }
        numInserted = len;
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
        inserter.close();

        endTime = System.currentTimeMillis();

        if (LOGV) {
            long timeTaken = (endTime - startTime);
            Log.v(TAG, "Time taken to insert " + values.length + " records was " + timeTaken + 
                    " milliseconds " + " or " + (timeTaken/1000) + "seconds");
        }
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return numInserted;
}
Run Code Online (Sandbox Code Playgroud)

  • 我在重写的bulkInsert方法中使用了事务,它将我的600个插入从31秒加速到1秒以下.我绝对推荐这种方法. (4认同)