Android SQLite在复杂查询中的表现

use*_*882 9 java sqlite android

假设我有这种查询

String sql = "SELECT s.team_id, s.team_name, s.gp, s.w, s.t, s.l, s.go, s.ga, s.score, s.p FROM "
           + "(SELECT team_id, team_name, SUM (gp) gp, SUM (w) w, SUM (t) t, SUM (l) l, SUM (GO) go, SUM (GA) ga, SUM (GO)- SUM (GA) score, SUM (2*w+t) p FROM "
           + "(SELECT t._id team_id, t.name team_name, COUNT(CASE WHEN score_home IS NOT NULL THEN 1 END) gp, COUNT (CASE WHEN score_home > score_away THEN 1 END) w,"
           + " COUNT (CASE WHEN score_home = score_away THEN 1 END) t, COUNT (CASE WHEN score_home < score_away THEN 1 END) l,"
           + " SUM (score_home) go, SUM (score_away) ga"
           + " FROM team_table t LEFT OUTER JOIN match_table m ON m.team_home = t._id"
           + " WHERE t.tournament_id = ? GROUP BY t._id, t.name"
           + " UNION ALL"
           + " SELECT t._id team_id, t.name team_name, COUNT(CASE WHEN score_away IS NOT NULL THEN 1 END) gp, COUNT (CASE WHEN score_home < score_away THEN 1 END) w,"
           + " COUNT (CASE WHEN score_home = score_away THEN 1 END) t, COUNT (CASE WHEN score_home > score_away THEN 1 END) l,"
           + " SUM (score_away) go, SUM (score_home) ga"
           + " FROM team_table t LEFT OUTER JOIN match_table m ON m.team_away = t._id"
           + " WHERE t.tournament_id = ? GROUP BY t._id, t.name)"
           + " GROUP BY team_id, team_name) s"
           + " ORDER BY s.p DESC, s.score DESC, s.go ASC";
Run Code Online (Sandbox Code Playgroud)

然后像这样使用

Cursor cursor = database.rawQuery(sql, args);

cursor.moveToFirst();
while (!cursor.isAfterLast()) {
    TeamStats stat = new TeamStats();

    stat.setTeamId(cursor.getLong(0));
    stat.setTeamName(cursor.getString(1));
    stat.setGamesPlayed(cursor.getInt(2));
    stat.setWins(cursor.getInt(3));
    stat.setTies(cursor.getInt(4));
    stat.setLoses(cursor.getInt(5));
    stat.setGoalsOwn(cursor.getInt(6));
    stat.setGoalsAgaist(cursor.getInt(7));
    stat.setScore(cursor.getInt(8));
    stat.setPoints(cursor.getInt(9));

    stats.add(stat);
    cursor.moveToNext();
}
cursor.close();
Run Code Online (Sandbox Code Playgroud)

因此,它从许多表中选择值,执行某些操作等.正如您所看到的,查询非常复杂(非常难以调试),并且性能似乎并不像我预期的那样好.我的问题是:

  1. 我可以使用某种准备好的声明来改善表现吗?
  2. 执行更简单的查询并使用一些自定义代码手动处理它们会更快吗?

mvp*_*mvp 6

如果我是你,我会将你的sqlite数据库复制到主机,然后尝试在某些SQLite GUI中手动执行它,同时用?你拥有的实际变量值替换绑定变量().对于Windows上的GUI,我非常喜欢SQLite Expert Personal,而且在Linux sqliteman上非常好.

在调试SQL时(在命令行或GUI中),请确保通过在EXPLAIN和/或下运行它们来分析SQL语句EXPLAIN QUERY PLAN.注意表扫描.您应该尝试通过添加索引来消除昂贵的扫描.但不要索引所有内容 - 它可能会使事情变得更糟.通常,使用复合(多列)索引可以大大提高性能.请注意,在任何给定的表上,SQLite不能仅使用一个索引(在运行给定的SQL语句时) - 因此,请明智地选择索引.(另请参阅查询计划中的基本说明.)

并且为了解决您对Java与SQLite中的数据处理的关注 - 我认为完全优化(使用适当的索引等)SQLite 对关系数据的查询将(几乎)总是比在Java中手动处理这些数据更快.在您的情况下尤其如此 - 您的所有数据基本上都是关系型的.

但需要注意的一点是:使用Java的Android APK可能比SQLite默认访问更多内存 - 您可能希望使用setMaxSqlCacheSize()(相当于PRAGMA cache_size)增加数据库的SQLite缓存大小.Android默认值为10(最多100),尝试增加它,看看你的查询是否有任何不同.请注意,此设置的桌面SQLite默认值要高得多 - 2000.