【问题标题】:SQLite - Speed up 4,000 row insert in Android appSQLite - 在 Android 应用程序中加速 4,000 行插入
【发布时间】:2015-06-23 14:25:51
【问题描述】:
public synchronized void updateStop(ArrayList<StopBean> beanList){
    SQLiteDatabase db = getWritableDatabase();
    String query = "DELETE FROM 'stop'";
    db.execSQL(query);
    for(StopBean bean : beanList){
        String atco_code = bean.getAtco_code();
        String name = bean.getName();
        String locality = bean.getLocality();
        String bearing = bean.getBearing();
        String latitude = bean.getLatitude()+"";
        String longitude = bean.getLongitude()+"";

        ContentValues values = new ContentValues();
        values.put("atco_code", atco_code);
        values.put("name", name);
        values.put("locality", locality);
        values.put("bearing", bearing);
        values.put("latitude", latitude);
        values.put("longitude", longitude);
        db.insert("stop", null, values);
    }

    db.close();
}

目前我们的应用程序通过上述方法插入了 4,000 行。这种方法的问题是实际执行需要 10-15 秒。显然,这对于简单的 4,000 行插入来说太长了。

如何更改此方法以大大加快这些插入的执行时间?

【问题讨论】:

  • 在后台线程上运行??
  • @iRaviiVooda 我是 Java 新手,但我相信这段代码已经在另一个线程上运行,类 implements Runnable 并且该方法在 override run 中调用。

标签: java android sqlite


【解决方案1】:

使用beginTransaction()endTransaction()markTransactionAsSuccessful() 将整个事物封装在一个事务中。现在,每次插入执行一个事务,这意味着每次插入需要一个磁盘 I/O 脉冲,这将非常慢。

除此之外:

  • 不要在循环的每次传递中分配新的ContentValues

  • 去掉局部变量(例如,atco_code),以防它们没有被优化掉

  • 使用比“”更有效的方式将数字转换为字符串(例如,Double.toString()

  • 尝试将纯 SQL INSERT 语句编译为 SQLiteStatement via compileStatement(),看看这是否比仅调用 insert() 更好

如果您仍然不满意,请使用 Traceview 并确定您剩余的时间都花在了哪里。

【讨论】:

    【解决方案2】:

    recent versions of sqlite(即 Kit Kat、Jelly Bean 和 Lollipop,according to the emulators)中,您可以使用多插入语句:

    INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2');
    

    如果您要导入静态 trusted 数据,请在您的应用程序的文件中包含带有数据的 sqlite 脚本,并在首次启动时运行它。注意:永远不要将 SQL 值连接到 SQL 查询中,因为这会为您打开数据库注入(并且它不会更快,因为您和 sqlite 将解析数据两次并进行不必要的重新序列化)。

    如果需要插入动态生成的数据或需要支持旧版本,则应使用准备好的语句预编译 SQL 查询并使用绑定变量。示例:

    db.beginTransaction();
    String sql = "INSERT INTO stop(atco_code, name, locality, bearing, latitude, longitude) VALUES (?,?,?,?,?,?)";
    SQLiteStatement stmt = db.compileStatement(sql);
    
    for(StopBean stop : stopList){
        stmt.bindString(1, stop.getAtco_code());
        stmt.bindString(2, stop.getName());
        stmt.bindString(3, stop.getLocality();
        stmt.bindString(4, stop.getBearing());
        stmt.bindDouble(5, stop.getLatitude());
        stmt.bindDouble(6, stop.getLongitude());
    
        stmt.execute();
        stmt.clearBindings();
    }
    
    db.setTransactionSuccessful();
    db.endTransaction();
    

    在所有情况下,您都应该将所有插入包装在一个事务中。使用单个事务允许数据库将值缓存在快速 RAM 中,并仅在缓存已满或完成时刷新数据,而不是为每个插入语句将数据刷新到持久存储。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-03
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 2019-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多