我正在为 iPad 开发一个企业销售应用程序,它使用 Sqlite 作为其内部数据库,最近出现了一种奇怪的行为。
我有一个巨大的表格,里面充满了来自其他几个表格的信息(有点像“物化视图”),它可以包含超过 200 万行,具体取决于用户的设置方式。当用户想要搜索一个项目时,应用程序会在这个具有索引列的巨大表以及用作过滤器和/或元数据的其他列上执行查询。我将在下面发布查询和基本思想。无论如何,这个查询在第四代 iPad 上通常会在 2~3 秒内返回,仅此而已,这很好。每次用户点击一个按钮以将他的数据与我们的服务器同步时,这个表就会被删除、重新创建和填充。
但是,最近在同一张表中的相同查询(根本没有相关更改),随机开始需要 40~50 秒。如果您稍后在同一设备上使用相同的过滤器(甚至更改过滤器!)执行相同的操作,同一张表上的相同查询再次需要 2~3 秒。我没有发现任何导致这种减速的具体情况,该应用程序是当时唯一运行的应用程序。设备不是问题,我们已经在至少 5 台不同的 iPad 上看到了这种情况,一台是 iPad 3,另一台是第四代 iPad。
我不认为这是某种缓存,因为应用程序不缓存任何东西,而且这些时间相当随机。有时他们连续 10 次需要 40 秒,然后突然又开始只需要 2 秒,反之亦然。我唯一清楚的是,这种减速只发生在密集使用后(使用该应用程序工作 1 到 2 天),所以在我随身携带的 iPad 上调试时,我也遇到了导致这种行为的麻烦。
我试过的:
- 将 Instruments 附加到流程并检查减速期间正在使用哪些资源。该应用程序在整个过程中都会大量使用 iPad 的“磁盘”(闪存)。我现在没有再分析的例子,但我认为 CPU 使用率在 30% 左右。RAM 使用量稳定在 90~100MB,这对于我们的应用来说是正常的。
- 在数据库上运行 VACCUM;- 在我作为示例的数据库上减少了约 50MB。从 ~600MB 到 ~550MB。
- 在数据库上运行分析;- 没有看到任何改进
- 在数据库上运行 REINDEX;- 似乎有点帮助,但它并没有解决问题。
- 终止进程并重新开始 - 没有任何变化
巨大的表构造如下,并且没有任何外键或其他任何其他约束:
CREATE TABLE FMV_CATALOG(
UNIQUE_ID TEXT,
PRODUCT_ID INTEGER,
<bunch of metadata/filtered columns - total of 20 columns>
);
查找产品的查询是:
SELECT
PRODUCT_ID
,UNIQUE_ID
<all other required columns, ~20 columns>
FROM
FMV_CATALOG
WHERE
UNIQUE_ID = '<some id>_<other id>'
AND PRODUCT_NAME LIKE '%iPhone%'
<和其他可选的,很少使用的过滤器。>
我完全没有想法,所以任何帮助将不胜感激。
谢谢!
更新(更多信息):
我忘记提及的重要信息,Rob让我想起了它。我的数据库连接始终处于打开状态,仅在用户注销时才关闭。当我们保持连接打开时,我们注意到应用程序的所有部分都有巨大的性能,因为我们有数百个在其他情况下执行的小查询(但不是在浏览/搜索产品目录时)。
用于创建索引的查询如下:
在 MV_CATALOG(UNIQUE_ID) 上创建索引 IDX_MV_CATALOG;
此外,即使该列被命名为 UNIQUE_ID,它也不是唯一的。本来应该是,现在重复了N次。我知道这是错误的,我们会尽快更改。
这个“UNIQUE_ID”(不是真正唯一的)是通过连接另外两个表的 ID 来填充的。这样,当用户在我们的目录上搜索时,我们的“物化视图”消除了至少三个连接的需要,这将我们的查询时间从大约 20 秒缩短到了大约 2 秒。
我们不会直接在查询中调用 sqlite3 API,我们围绕它开发了一个包装类,并且我们已经使用它至少 2 年了。这是我们第一次遇到这种情况,但这也是我们第一次处理如此多的数据。