假设我有一个表示固定深度层次结构的模式,如下所示:
CREATE TABLE level0 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL
)
CREATE TABLE level1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
level0_id INTEGER NOT NULL
)
CREATE TABLE level2 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
level1_id INTEGER NOT NULL,
is_important INTEGER
)
CREATE INDEX level2_level1_id ON level2 (level1_id)
CREATE INDEX level1_level0_id ON level1 (level0_id)
(只是为了给出一定的比例感,在level1中假设1000行,在level1中为2000,在level2中为20000,这是手机sd卡上的sqlite数据库。等级0查询返回最多1000行,level1查询返回1 -30行,level2查询返回1-20行)
我一次只显示一个级别的层次结构。所以我显示三个级别中的每一个的查询都是这样的:
SELECT id,text FROM level0
SELECT id,text FROM level1 WHERE level0_id = 12345
SELECT id,text FROM level2 WHERE level1_id = 23456
简单,快速,完全索引。现在,我还想显示相同的层次结构,除了我想基于is_important过滤它。我只想显示最终通过is_important = 1导致level2行的level0和level1行。
所以我写了一些新的查询,与旧的查询非常不同。
level 0:
SELECT DISTINCT l0.id,l0.text
FROM level2 AS l2
INNER JOIN level1 AS l1 ON l1.id = l2.level1_id
INNER JOIN level0 as l0 on l0.id = l1.level0_id
WHERE l2.is_important = 1
level 1:
SELECT DISTINCT l1.id,l1.text
FROM level2 AS l2
INNER JOIN level1 AS l1 ON l1.id = l2.level1_id
WHERE l2.is_important = 1
level 2:
SELECT id,text FROM level2 WHERE level1_id = 23456 AND is_important = 1
0级和1级查询显然比上面未经过滤的查询慢得多。我明白为什么他们很慢,但我在改善他们的表现时遇到了麻烦。
通过遍历最大的表来提取较小的表,我觉得很奇怪,但这似乎是用SQL可以理解的表达我想要的最简洁和自然的方式。
所以我的问题是:你如何改善上面过滤的0级和1级查询的性能?
答案 0 :(得分:0)
我建议您查看两个查询(已过滤和未过滤)的计划,以了解未过滤查询为何如此缓慢。纯粹猜测,但如果只有索引在每个表的ID列上,那么数据库可能决定在level2表中顺序遍历以查找IS_IMPORTANT = 1的那些行。
要尝试影响这一点,请尝试在level2上添加索引(level1_id,is_important)。这会将各种查询的WHERE子句中使用的所有列放入索引中。看起来这也应该有助于其他查询。
分享并享受。
答案 1 :(得分:0)
内部联接的快速技巧:SMALL_TABLE INNER JOIN BIG_TABLE
比反向快。
在您的情况下,请尝试最后添加您的level2表。
答案 2 :(得分:0)
您是否尝试过更改
CREATE INDEX level2_level1_id ON level2(level1_id)
到
CREATE INDEX level2_level1_id ON level2(level1_id,is_important)?
答案 3 :(得分:0)
我最终得到了一个更快的查询,该查询使用了不同的技术并避免了最昂贵的连接。在应用此线程中的所有建议后,这比我最终得到的查询快约3倍。重新排序连接使我走上了最终消除一个连接的道路(并且自身也获得了最佳性能提升),所以我接受了这个答案。
我现在要进行的查询是:
level 1:
SELECT l1.id,l1.text
FROM level1 AS l1
WHERE EXISTS
(SELECT * FROM level2 AS l2 WHERE l2.level1_id = l1.id AND l2.is_important)
level0查询是两种方法的混合 - 我在level0和level1上加入,但是使用嵌套查询过滤level2。