SQLite - 在 Android 应用程序中加速 4,000 行插入
SQLite - Speed up 4,000 row insert in Android app
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 行插入来说太长了。
如何更改此方法以大大加快这些插入的执行时间?
使用 beginTransaction()
、endTransaction()
和 markTransactionAsSuccessful()
将整个事务包装在事务中。现在,每次插入执行一个事务,这意味着每次插入一个磁盘脉冲 I/O,这将非常慢。
除此之外:
不要在循环的每一遍中分配一个新的ContentValues
去掉局部变量(例如,atco_code
),以防它们没有被优化掉
使用比“”更有效的方法将数字转换为字符串(例如,Double.toString()
尝试将普通 SQL INSERT
语句编译为 SQLiteStatement
via compileStatement()
,看看这是否比仅调用 insert()
如果您仍然不满意,请使用 Traceview 并确定您剩余的时间都花在了哪里。
在recent versions of sqlite (which is Kit Kat, Jelly Bean, and 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 中,并仅在缓存已满或完成时刷新数据,而不是为每个插入语句将数据刷新到持久存储。
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 行插入来说太长了。
如何更改此方法以大大加快这些插入的执行时间?
使用 beginTransaction()
、endTransaction()
和 markTransactionAsSuccessful()
将整个事务包装在事务中。现在,每次插入执行一个事务,这意味着每次插入一个磁盘脉冲 I/O,这将非常慢。
除此之外:
不要在循环的每一遍中分配一个新的
ContentValues
去掉局部变量(例如,
atco_code
),以防它们没有被优化掉使用比“”更有效的方法将数字转换为字符串(例如,
Double.toString()
尝试将普通 SQL
INSERT
语句编译为SQLiteStatement
viacompileStatement()
,看看这是否比仅调用insert()
如果您仍然不满意,请使用 Traceview 并确定您剩余的时间都花在了哪里。
在recent versions of sqlite (which is Kit Kat, Jelly Bean, and 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 中,并仅在缓存已满或完成时刷新数据,而不是为每个插入语句将数据刷新到持久存储。