SQL:如何在根据外部数据过滤行时提高性能?

时间:2010-08-17 08:56:49

标签: sql sqlite

假设我有一个表示固定深度层次结构的模式,如下所示:


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级查询的性能?

4 个答案:

答案 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。