【问题标题】:android and sqlite performanceandroid 和 sqlite 性能
【发布时间】:2013-03-03 19:35:49
【问题描述】:

我在使用 sqlite 和 Android 2.3.7 时遇到严重的性能问题。

我要存储少量数据:14 行,每行 8 列。从网页读取数据;解析数据时,我将删除数据库的全部内容,然后一次性批量插入新数据。

一些(已编辑的)LogCat 输出:

03-15 14:39:51.909: Got content downloaded.
03-15 14:39:52.299: Deleting existing info from db.
03-15 14:39:52.719: Bulk inserting new data into db.
03-15 14:40:00.709: Stored data in the database.

我正在使用 ContentProvider 来访问数据库。

解析页面需要 0.4 秒。

删除需要 0.4 秒。

bulkInsert 需要 8 秒。

所有数据的后续查询和读取再次需要大约 0.4 秒。

相关代码sn-p:

    Log.v(TAG, "Deleting existing info from db.");
    delete(API_TABLE, null, null);
    Log.v(TAG, "Bulk inserting new data into db.");
    bulkinsert(API_TABLE, allValues);
    Log.v(TAG, "Stored data in the database.");

字段和类型数据:

public final static String[] API_KEYS = {KEY_STATION, KEY_API, 
    KEY_POLLUTANT, KEY_SO2, KEY_NOX, KEY_CO, KEY_PHOTO, KEY_TSPRSP, 
    KEY_RSP};
public final static String[] API_TYPES = {"TEXT PRIMARY KEY", "TEXT", 
    "TEXT", "TEXT", "TEXT", "TEXT", "TEXT", "TEXT", "TEXT"};

数据库构建是这样完成的:

        StringBuilder dbCommand = new StringBuilder();
        dbCommand.append("CREATE TABLE " + API_TABLE + " (");
        dbCommand.append("'" + API_KEYS[0] + "' " + API_TYPES[0]);
        for (Integer i = 1; i < API_KEYS.length; i++)
            dbCommand.append(", '" + API_KEYS[i] + "' " + API_TYPES[i]);
        dbCommand.append(");");
        Log.v(TAG, "Creating API database now.");
        db.execSQL(dbCommand.toString());

要插入的值存储在 ContentValues[] 对象中,然后使用

context.getContentResolver().bulkInsert(API_URI, values);

关于如何改进这一点的任何想法?尤其是插入时间太长了。

【问题讨论】:

  • 我不太确定您是如何实现“批量插入”的。您是否在单个事务中执行此操作,是否尝试过来自 outofwhatbox.com/blog/2010/12/… 的指针?
  • 批量插入是通过调用 context.getContentResolver().bulkInsert(API_URI, values);使用 values 一个 ContentValues 列表,每个 ContentValues 都包含单行的数据。编辑问题以反映这一点。

标签: java android performance sqlite


【解决方案1】:

使用SQLiteDatabase 类进行此操作。

我用下面的方法插入,比较快

public void createContatctDirectory(ArrayList<String> data) {
    SQLiteDatabase db = context.openOrCreateDatabase(DATABASE_NAME,
            Context.MODE_PRIVATE, null);

    InsertHelper ih = new InsertHelper(db, TABLE_NAME);
    Iterator<String> it = data.iterator();
    final int numberColumn = ih.getColumnIndex(KEY_NUMBER);

    db.beginTransaction();
    int count = 0;
    try {
        while (it.hasNext()) {
            ++count;
            String ph;
            ph = it.next();
            ih.prepareForInsert();
            ih.bind(numberColumn, ph);

            ih.execute();
        }
    } finally {
        ih.close();
        db.setTransactionSuccessful();
        db.endTransaction();
        db.close();
    }
}

【讨论】:

  • @CL context.getContentResolver().bulkInsert 是否与 SQLiteDatabase 一样工作?我不知道
  • 它以相同的数据库对象结束。仅当您想调用 SQLiteDatabase 对象上的其他函数(但您没有提及)时,这才会有所不同。
  • @CL 它是通过 ContentProvider 间接完成的。 bulkInsert 方法也是 ContentProvider 类的一部分。在这种情况下,不能直接调用 SQLiteDatabase。
【解决方案2】:

根据 StinePike 的回复,我将提供程序类更改为包括:

@Override
public int bulkInsert(Uri uri, ContentValues[] values) {

    String table = getTable(uri);
    int count = 0;
    for (ContentValues value : values) 
        count += db.insert(table, "", value);

    return count;

}

这会稍微缩短插入时间,但对于仅 14 个值而言,4-5 秒仍然有点长。

然后在这个方向上进行更多搜索,我发现了一个不同的解决方案here,它确实加快了速度,我现在只用了不到 1 秒。这是可以接受的,我认为不能再改进了。此代码是我的 ContentProvider 扩展类的一部分。

    @Override
public int bulkInsert(Uri uri, ContentValues[] values) {
    try {
        db.beginTransaction();
        String table = getTable(uri);
        for (ContentValues value : values)
            db.insert(table, null, value);
        db.setTransactionSuccessful();
    } catch (SQLException e) {
    } finally {
        db.endTransaction();
    }
    return values.length;   
}

【讨论】:

  • 虽然这可能没有太大帮助,但您也应该只使用一次getTable(uri)。无需在每次迭代中重新解析表名。第二个参数nullColumnHack 应该是null。最后:您的count 值将是错误的。方法insert()返回行的id。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
  • 2016-10-08
  • 2012-01-14
  • 2012-07-08
  • 1970-01-01
  • 2012-08-26
  • 2011-10-27
相关资源
最近更新 更多