文章目录

老大交给了一个任务,其他项目组在应用初始化时,需要从服务器下载通讯录,然后插入到本地数据,由于数据量比较大,整个插入过程非常耗时,看我能不能优化一下。于是就有了下文。

SQL执行性能影响从根本原因上不外乎以下几种情况:

1.CPU执行时间;

2.存储器读写时间;

3.网络传输消耗。

第1点针对CPU可以做的优化有使用预处理,防止CPU多次解析SQL语句;第2点针对存储器读写时间的优化有使用事务,将数据写全部写入到内容,然后一次性写入到本地存储空间,当然这需要足够的内存空间,否则会导致内存溢出,这个问题在android开发尤其重要,不然App会退出运行。第3点在android开发中基本用不到,所以只针对前面两点考虑优化。

下面是优化的案例,数据是从网上下载的号码归属地XLS数据,总共65535行数据,老大说通讯录的数据也有几万条,正好可以用这个数据做测试,只不过XLS数据每行数据差别不大,很有规律,通过跟真实数据测试发现,差别不大。

按照上面的思路,基本告别android.content.ContentValues类,得自己拼接SQL,再使用SQLiteDatabse.execSQL()执行预处理。

下面代码是表结构(没有从代码中整理成表格,大概能知道有几个字段及字段的类型):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

db.execSQL(“CREATE TABLE “ + TelColumns.TABLE_NAME + “ (“
+ TelColumns._ID + “ INTEGER PRIMARY KEY,“
+ TelColumns.ID + “ TEXT,“
+ TelColumns.TEL + “ TEXT,“
+ TelColumns.CODE + “ TEXT,“
+ TelColumns.ADDRESS + “ TEXT,“
+ TelColumns.TYPE + “ TEXT,“
+ TelColumns.DATE + “ INTEGER“
+ “);“);

public class TelColumns implements BaseColumns {

public static final String TABLE_NAME = “tel“;
public static final String ID = “id“;
public static final String TEL = “tel“;
public static final String CODE = “code“;
public static final String TYPE = “name“;
public static final String ADDRESS = “depart“;
public static final String DATE = “date“;

}

下面代码使用了事务和和预处理的SQL,data数据来源于对XLS数据的解析。在开始执行事务时开始记时,完成后关闭数据库记时结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

void insertByRaw(List<DemoItem> data) {
final int size = data.size();
final int idx = size;
TelDatabase db = new TelDatabase(getApplicationContext());
SQLiteDatabase sqliteDB = db.getWritableDatabase();
long start = System.currentTimeMillis();
sqliteDB.beginTransaction(); // 事务开始
DemoItem item = null;
StringBuilder sb = new StringBuilder();
sb.append(“INSERT INTO “).append(TelColumns.TABLE_NAME)
.append(“(“)
.append(TelColumns.ID).append(“,“)
.append(TelColumns.TEL).append(“,“)
.append(TelColumns.CODE).append(“,“)
.append(TelColumns.ADDRESS).append(“,“)
.append(TelColumns.TYPE).append(“,“)
.append(TelColumns.DATE)
.append(“)“)
.append(“ VALUES(?,?,?,?,?,?)“); // 预处理SQL
String sql = sb.toString();
SQLiteStatement stmt = sqliteDB.compileStatement(sql);
try {
for (int i = 0; i < idx; i++) {
item = data.get(i);
stmt.bindString(1, item.id);
stmt.bindString(2, item.tel);
stmt.bindString(3, item.code);
stmt.bindString(4, item.address);
stmt.bindString(5, item.type);
stmt.bindLong(6, System.currentTimeMillis());
stmt.execute();
}
sqliteDB.setTransactionSuccessful();
} finally {
sqliteDB.endTransaction();
stmt.close();
}

long end = System.currentTimeMillis();
sqliteDB.close();
Log.d(TAG, “used time: “ + (end - start) + “, nums: “ + idx + “, average item: “ + (end - start) / size);
// used time: 5616, nums: 65536, average item: 0
// used time: 5720, nums: 65536, average item: 0
// used time: 5615, nums: 65536, average item: 0

}

上面代码在我的MOTO G XT1032手机上测试,耗时在5.6秒上下波动,上面注释的used time代码即为实际运行时间的随机值。数据插入完成后整个数据库文件有4.48M。

后面用android.content.ContentValues类和SQLiteDatabase.insert()方法,同样加了事务测试了一下,运行耗时在17秒左右。很明显,慢了很多。

So,测试到这儿任务结束了吗?前面的优化方法估计一般开发都能做到,那还有没有优化的空间?如果要体现自己的优势,那么就要寻找耗时更短的优化方式。后面还有性能提升的空间,请看下一篇android SQLite性能优化(二)——使用NDK优化

文章目录