今天在优化公司项目中,发现一个列表在离线加载时速度非常慢,加载1000条数据,竟然需要13s!!!
跟了一下db层代码
@Override
public ArrayList<Task> loadMineTask(String userId,boolean noblongs) {
.....//省略
Cursor cursor = db.rawQuery(sql,null);
while (cursor.moveToNext()) {
Task task = getFromCursor(cursor,false,false);
tasks.add(task);
}
cursor.close();
.....//省略
return tasks;
}
发现在执行rawQuery都是毫秒级,99%的时间集中在了getFromCursor(…)这个方法中了,继续跟踪:
private Task getFromCursor(Cursor cursor,boolean isLoadAllInfo,boolean isLoadStages) {
.....//省略
String parentId = cursor.getString(cursor.getColumnIndex(FIELD_PARENT));
if (!TextUtils.isEmpty(parentId)) {
Task parentTask = loadTask(parentId);
task.setParent(parentTask);
}
// 负责人
String managerId = cursor.getString(cursor
.getColumnIndex(FIELD_MANAGER));
if (!TextUtils.isEmpty(managerId)) {
EmployeeInfo manager = employeeDao.loadUser(managerId);
if (manager != null)
task.setManager(manager);
}
// 创建人
String authorId = cursor.getString(cursor.getColumnIndex(FIELD_AUTHOR));
if (!TextUtils.isEmpty(authorId)) {
EmployeeInfo author = employeeDao.loadUser(authorId);
if (author != null)
task.setCreator(author);
}
if (isLoadAllInfo) {
// Tag
ArrayList<Tag> tags = tagDao.loadTagByTargetId(taskId);
task.setTags(tags);
ArrayList<ShareEntry> shareEntries = new ArrayList<ShareEntry>();
shareEntries = shareEntryDao.loadShareEntriesByTargetId(taskId);
task.setShareEntrys(shareEntries);
// mainLine 主线
ArrayList<Mainline> mainLines = mainLineDao
.loadMainlinesByTargetId(taskId);
task.setMainlines(mainLines);
// attachment
ArrayList<Attachment> attachments = attachmentDao
.loadAttachmentsByRefId(taskId);
task.setAttachments(attachments);
// 关联
ArrayList<Relevance> relevances = relevanceDao
.loadRelevances(taskId);
task.setRelevances(relevances);
}
return task;
}
天了噜,在一个本来cursor转model的方法中,竟然还有这么多loadFromDb的操作,1000条数据,可是从对数据库进行1000*N次操作啊,毫秒级的操作累计起来突破10s也不是难题!
着手解决,是否可以做一次查询,把需要的数据从多表中组合起来?
//不建议
select table1.abc from table1,table2 where table1.xxx=table2.xxx;
实测了一下,这种方法的复杂度是join关键字的几何级倍数,用join的关键语句如下
select table1.abc from table1 inner join table2 on table1.xxx=table2.xxx;
其中join有三种用法:
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
inner join(等值连接) 只返回两个表中联结字段相等的行
举例如下:
表A记录如下:
aID aNum
1 a20050111
2 a20050112
3 a20050113
4 a20050114
5 a20050115
表B记录如下:
bID bName
1 2006032401
2 2006032402
3 2006032403
4 2006032404
8 2006032408
1.left join
sql语句如下:
select * from A
left join B
on A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
5 a20050115 NULL NULL
(所影响的行数为 5 行)
结果说明:
left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的.
换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID).
B表记录不足的地方均为NULL.
2.right join
sql语句如下:
select * from A
right join B
on A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
NULL NULL 8 2006032408
(所影响的行数为 5 行)
结果说明:
仔细观察一下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充.
3.inner join
sql语句如下:
select * from A
innerjoin B
on A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
结果说明: 很明显,这里只显示出了 A.aID = B.bID的记录.这说明inner join并不以谁为基础,它只显示符合条件的记录.