[英]Firebird 2.5 SQL query execution plan not using index with OR statement
首先:我不是數據庫專家,所以請沉迷於這個問題。
我在子表CHILD
上有一個查詢,在主表PARENT
查找一些值以確定是否要加載該條目。
查詢看起來像這樣
SELECT C.*, P.DATE, P.STATUS
FROM CHILD C, PARENT P
WHERE C.PARENT_ID = P.ID
AND (P.DATE > '01.01.2015' OR (P.STATUS <> 1 AND P.STATUS <> 9));
我選擇STATUS
值是為了突出顯示我需要使用不等式,因為我需要從中選擇不連續的狀態值。
我在PARENT.ID
上具有外鍵CHILD.PARENT_ID
,並在CHILD.PARENT_ID
上創建了索引。 我還在DATE
和STATUS
字段的表PARENT
上創建了索引。
現在,當我更換OR
用和AND
CHILD
使用的指數PARENT_ID
和PARENT
使用的指標DATE, STATUS
這是我所期望的。
但是當使用OR
,查詢將對CHILD
使用自然計划,對PARENT.ID
使用主鍵索引。
如果僅將查詢應用於父表,則會發生相同的情況:
SELECT P.* FROM PARENT P WHERE (P.DATE > '01.01.2015' OR (P.STATUS <> 1 AND P.STATUS <> 9));
有沒有一種方法可以優化這種查詢,使其比自然計划更好地使用?
如果您輸入“或”,則每個P.DATE都可能會命中。 同樣,每個P.STATUS都可能會受到打擊。 如果要使用索引,這不是很好的前提條件。
在這里,您將需要幫助您的系統,並提出2個獨立的問題,並將它們與UNION連接起來。 喜歡
SELECT C.*, P.DATE, P.STATUS
FROM CHILD C, PARENT P
WHERE C.PARENT_ID = P.ID
AND P.DATE > '01.01.2015'
UNION
SELECT C.*, P.DATE, P.STATUS
FROM CHILD C, PARENT P
WHERE C.PARENT_ID = P.ID
AND P.STATUS <> 1
AND P.STATUS <> 9;
注意:如果P.STATUS的大多數值不等於1和不等於9,您的性能仍然會很差。 試想一下,您正在尋找一本書,其中所有詞都已索引,單詞“和”。 它會出現在每一頁上; 順序閱讀本書要比使用索引快。
對於優化器來說,使用索引很難。 首先,使用join
重寫查詢:
SELECT C.*, P.DATE, P.STATUS
FROM CHILD C JOIN
PARENT P
ON C.PARENT_ID = P.ID
WHERE P.DATE > '2015-01-01' OR P.STATUS NOT IN (1, 9);
您可以使用UNION ALL
重寫此代碼:
SELECT C.*, P.DATE, P.STATUS
FROM CHILD C JOIN
PARENT P
ON C.PARENT_ID = P.ID
WHERE P.DATE > '2015-01-01'
UNION ALL
SELECT C.*, P.DATE, P.STATUS
FROM CHILD C JOIN
PARENT P
ON C.PARENT_ID = P.ID
WHERE P.DATE <= '2015-01-01' AND -- This condition prevents overlaps
P.STATUS NOT IN (1, 9);
現在,子查詢可以使用PARENT(DATE, ID)
和PARENT(STATUS, DATE, ID)
上的索引。
但是,尚不清楚篩選結果是否會真正使查詢更快。 這取決於過濾器的選擇性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.