2010-08-17 27 views
1

說我有一個代表一個固定深度的層次結構是這樣的模式:SQL:如何在基於外部數據過濾行時提高性能?


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) 

(只給規模感,假設1000 rowsin 0級,2000年在1級,並在level2的20000,這是一個sqlite數據庫在手機的SD卡上。0級查詢返回1000行,1級查詢返回1-30行,2級查詢返回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進行過濾。我只想顯示level0和level1行,最終導致level2行,is_important = 1。

因此,我寫了一些新的查詢,與舊的很不同。


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

內連接的快速技巧:SMALL_TABLE INNER JOIN BIG_TABLE快於反向。

在你的情況,最後嘗試添加你的level2表。

+0

謝謝。這加快了一點。 – blucz 2010-08-17 22:11:06

0

我建議看看兩個查詢(過濾和未過濾)的計劃,看看爲什麼未過濾的查詢是如此之慢。純粹猜測,但是如果唯一索引位於每個表的ID列上,那麼數據庫可能會決定順序遍歷level2表以找到IS_IMPORTANT = 1的那些行。

要嘗試並影響這一點,嘗試在level2上添加索引(level1_id,is_important)。這將所有在各種查詢的WHERE子句中使用的列放入索引中。它看起來應該對其他查詢也有幫助。

分享和享受。

0

你有沒有試圖改變

CREATE INDEX ON level2_level1_id級別2​​(level1_id)

CREATE INDEX ON level2_level1_id級別2​​(level1_id,is_important)?

+0

這有幫助,謝謝。 – blucz 2010-08-17 22:34:17

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) 

的0級查詢是這兩種方法的混合 - 我同在0級1級和,但使用嵌套查詢過濾器(第二級)。