簡體   English   中英

Firebird 2.5 SQL查詢執行計划未在OR語句中使用索引

[英]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上創建了索引。 我還在DATESTATUS字段的表PARENT上創建了索引。

現在,當我更換OR用和AND CHILD使用的指數PARENT_IDPARENT使用的指標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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM