2011-12-13 157 views
0

我被困在一個查詢,需要您的幫助和suggestion.The的情況是:如何寫這個查詢

我有結構的表作爲

JOB_ID,ITEM_ID,NEW_ITEM_ID,STATUS

其中,job_id是主鍵,狀態可以是AC,SB。

現在我想寫一個查詢,只選擇那些STATUS作爲AC的表中沒有ITEM_ID或NEW_ITEM_ID的行中狀態爲SB.I已經寫了查詢但它需要很多的時間,請您幫我寫優化query.This我所寫的

SELECT * FROM (
     SELECT JOB_ID,NEW_ITEM_ID,ITEM_ID,STATUS 
     FROM X1 
     WHERE STATUS='AC' 
     AND NEW_ITEM_ID IS NOT NULL 
     MINUS 
     (SELECT T1.JOB_ID,T1.NEW_ITEM_ID ,T1.ITEM_ID ,T1.STATUS 
     FROM (SELECT * 
       FROM X1 
       WHERE STATUS IN 'AC' 
       AND NEW_ITEM_ID IS NOT NULL ) T1 
     , (SELECT * 
      FROM X1 
      WHERE STATUS IN ('PR','SB') 
      AND NEW_ITEM_ID IS NOT NULL ) T2 
    WHERE (T2.ITEM_ID IN (T1.ITEM_ID,T1.NEW_ITEM_ID) 
        OR T2.NEW_ITEM_ID IN (T1.ITEM_ID,T1.NEW_ITEM_ID) 
     ) 
    AND T1.STATUS!=T2.STATUS 
    ) 
) T 

編輯

此表將包含數百萬條記錄30M左右說。

+2

你有忘了在標籤中指定`firebird`和`db2` – zerkms 2011-12-13 19:56:56

+0

heh。@Algorithmist:你正在使用哪個DBMS? – 2011-12-13 19:57:54

+0

@Tomalak oracle 11g。 – Algorithmist 2011-12-13 20:01:37

回答

1

最簡單的方法是將有選擇所有ITEM_IDS和NEW_ITEM_IDs其狀態爲SB查詢,則有另一種這樣的查詢:

SELECT * FROM table WHERE STATUS = 'AC' AND WHERE ITEM_ID NOT IN (the results of the previous query) AND WHERE NEW_ITEM_ID NOT IN (the results of the query for NEW_ITEM_IDs mentioned above)

只是一個想法,但有了正確的語法,我認爲這應該工作。

0

試試這個:

select * from status where STATUS ='AC' or (STATUS ='SB' and ITEM_ID is null) or or (STATUS ='SB' and NEW_ITEM_ID is null) 
0

這聽起來像你正在尋找(1)式中的地位是交行(2)沒有其他排在ITEM_ID或new_item_id的比賽中,狀態爲SB ?

如何:

SELECT job_id, item_id, new_item_id, status 
    FROM x1 a 
WHERE a.status = 'AC' 
    AND NOT EXISTS (SELECT 1 FROM x1 b 
        WHERE b.status = 'SB' 
         AND (b.new_item_id = a.item_id 
          OR b.item_id = a.new_item_id) 
0

「此表將包含數百萬條記錄說周圍30M」

這是一個關鍵部分的信息,但其他幾個關鍵的統計信息缺失。 「PR」,「SB」和「AC」的狀態有多少行? new_item_id填充了多少行?這些列是否被索引?

您在子查詢中選擇* from x1'。 SELECT *是不好的做法,一個等待發生的錯誤。然而,這是災難性的,因爲您不使用任何列,但是您迫使數據庫讀取結果集中每個條目的整個行。行越長,價格越高。在子查詢中,如果你可能這樣做,你真的應該開始索引索引。

理想情況下,您將在X1(STATUS,NEW_ITEM_ID,ITEM_ID,JOB_ID)上有一個索引。那麼你根本不會碰到桌子。但至少你需要一個索引(STATUS,NEW_ITEM_ID)。 STATUS上的索引不會對你有任何好處,除非STATUS具有很高的選擇性 - 數百個不同的值,均勻分佈。 (這似乎不太可能:根據我的經驗,大多數狀態欄有幾個不同的狀態_。

您發佈的查詢命中了三次表X1;這需要很長時間,所以最主要的是減少點擊次數表。這是子查詢的保理可以幫助:

with data as ( select job_id, new_item_id, item_id, status 
       from x1 
       where status in ('PR','SB', 'AC') 
       and new_item_id is not null) 
select t1.* 
from data t1 
    , data t2 
where t1.status = 'AC' 
and t2.status in ('PR','SB') 
abd (t2.new_item_id in (t1.new_item_id, t1.item_id) 
    or t2.item_id in (t1.new_item_id, t1.item_id)) 
/

所以此查詢打表一次,並且具有良好的索引一次也沒有。

如果查詢仍然需要太多時間 - 或者您不能纏繞有用的索引 - 用於改善對大量表執行時間的另一選項是並行查詢。此選項是開放給你,如果你有一個企業版許可證,並有足夠的CPU的服務器(如果要運行多萬行的tables_應用程序數據庫這兩個條件應該是真實的。

with data as ( select /*+ parallel (x1, 4) */ 
         job_id, new_item_id, item_id, status 
       from x1 
       ...