【问题标题】:SQLite Query runs way slower on Android LollipopSQLite Query 在 Android Lollipop 上运行速度较慢
【发布时间】:2015-04-01 22:46:38
【问题描述】:

我有一个查询在 Gingerbread 设备和 Jellybean 上运行得非常好,但在 Lollipop 设备上运行速度要慢很多。我确定查询是正确的并且写得很好,因为它在旧设备上运行良好。

Cursor c;
String query = QUERY STRING;

c = db.rawQuery(query,new String[]{Integer.toString(a),Integer.toString(b)});

Log.e("SQL_QUERY_PROGRESS","1");

while(c.moveToNext()){
    Log.e("SQL_QUERY_PROGRESS","2");
    // Do stuff with data
}

c.close();

在 Gingerbread 设备上,两条日志消息之间只有 0.008 秒的间隔,而在 Lollipop 设备上则需要约 8 秒,这非常慢。

我无法理解的是,Lollipop 设备较新,并且具有更多 RAM、CPU 能力等,因此逻辑上肯定较新设备应该比旧设备更快地运行查询。

Lollipop 上使用的 Java 版本是否存在错误,或者 SQLite 版本是否会导致速度大幅下降?

我用过adb shell 并导航到数据库文件并在 Lollipop 设备上使用 sqlite3 运行查询,它几乎立即运行,这让我认为这更像是 Java 问题而不是 SQLite 问题。

我完全不知道可能导致延迟的原因,因此非常感谢任何帮助或想法,以便我可以进一步调查!

【问题讨论】:

  • Lollipop 设备通常对userdata 分区进行加密 - 这会减慢许多与存储相关的操作,包括数据库访问。除此之外,更新的设备并不总是转化为更快的存储。有很多因素在起作用。因此,除非您想在不同 android 版本下的同一设备上的同一数据集上运行查询并提供更多信息 - 您的问题没有实际意义且离题
  • 您是在主线程中运行查询还是在单独的线程中运行(AsyncTask、Thread、IntentService...)?
  • @Sunil 我让它在主线程中运行。在 Gingerbread 和 Jellybean 设备上的主线程中很好,因为它几乎立即执行,但不适用于 Lollipop
  • @PriestVallon - 我没有投反对票(我很少投反对票)......但回到你的问题,只有这个特定的查询才会这样做吗?因为在大约 8 秒时,我确信应用程序应该触发可怕的应用程序无响应 (ANR)。我建议您使用 TraceView 找出发生了什么并在另一台设备上试用该应用程序。还有你要返回多少行?
  • 你没有抓住重点。我可以轻松地将查询移动到不同的线程,但我仍然需要在 Lollipop 设备上等待约 8 秒,这并不令人满意。

标签: android performance sqlite android-5.0-lollipop


【解决方案1】:

这是我解决这个问题的方法。

  1. 首先,您需要确定哪些查询是有问题的。我通过用我自己的方法替换所有rawQuery() 调用来做到这一点。它将记录每次查询之间的时间。
private static Cursor runQuery(String query) {
    System.out.println("QUERY: " + query);
    Cursor tmpCursor = DatabaseManager.getInstance().openDatabase().rawQuery(query, null);
    System.out.println("TIME: " + (System.currentTimeMillis() - Main.time));
    Main.time = System.currentTimeMillis();
    return tmpCursor;
}

检查您怀疑的代码中其他部分的时间。 现在,您将看到在哪些查询之间丢失了时间。它实际上是游标逻辑,例如 c.moveToFirst() 是昂贵的。在这些之后进行时间检查,以进行验证。

  1. 找到查询后,检查它并检查查询必须经过哪些列。在我的情况下,我在具有大量行的表中的列上进行了连接。这是您下一步需要的列:
  2. 为此列创建索引,如下所示:
    CREATE INDEX idx_bibref ON responses(bibreference);

您可以在终端中运行它以进行测试(sqlite3),或者更好地将其放入您的onUpgrademethod。 就是这样。现在所有游标方法都再次快速运行,就像在以前的 Android 版本上一样。


旧帖:

我遇到了同样的问题。我让它在异步任务中运行,所以我可以确认正如 PriestVallon 所说,这在主 UI 线程上运行,虽然效率不高,但不是问题的原因。 它只出现在棒棒糖上。用 4.4 在手机和模拟器上运行这个。没有问题。 到目前为止,我的调查表明它与游标逻辑而不是查询本身有关。例如:

c.moveToFirst();
c.moveToNext();
c.getCount();
etc... 

通常在使用连接的更复杂查询之后运行(但我还不能 100% 确认)。

也许这会有所帮助。

(我很抱歉把这个放在答案中,反对评论,但我没有足够的声誉来发表评论。)

【讨论】:

  • 我也遇到过这个问题。我也很想知道根本原因是什么。
【解决方案2】:

我遇到了类似的问题 - 在 Lollipop 之前运行良好的 SQLite 查询在 Lollipop 上运行的速度要慢很多。这是对 3 个连接表的查询,耗时超过 10 秒!

在尝试了各种各样的事情之后,我发现了问题:Lollipop 使用 SQLite 3.8,它使用了不同的查询优化器,并且由于某种原因,它在其中一个连接中使用了错误的索引。

从我的测试设备上获取数据库副本后,我使用了命令行 SQLite 工具,并在查询中使用了“解释查询计划”。比较 pre-3.8 和 post-3.8 的输出,后者使用了不同且不正确的索引。

根据我的阅读,在数据库上运行“ANALYZE”可能已经修复了它,但由于我真的不需要它使用的错误索引,所以我只是删除了索引。现在查询使用了正确的索引,查询又快了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 2021-11-03
    • 2012-03-14
    • 1970-01-01
    相关资源
    最近更新 更多