2016-09-28 63 views
1

我們已經有了一個系統,其中包含一系列項目(> 100萬)以及處理它的幾件事情。每個處理器應該只處理每個項目一次,並且處理器具有層次結構。非常快速地從NOT IN查詢中返回結果

我們當前的實現是有一個什麼樣的每個處理器已經做了「處理」表保持跟蹤:

CREATE TABLE items (id NUMBER PRIMARY KEY, ...) 
CREATE TABLE itemsProcessed(
    item NUMBER REFERENCES items(id), 
    processor NUMBER) 

我們的查詢是這樣的(itemsProcessed已經得到了它的相關指標) - 我們使用一個NOT IN過濾掉那些已經被當前的處理器處理的項目,或者它的祖先:

SELECT ... FROM items i WHERE <additional queries on items> 
    AND id NOT IN (SELECT item FROM itemsProcessed WHERE processor IN (1, 2)) 

當處理表變得非常大,這個查詢開始花費很長的時間(幾秒鐘),因爲它做很多過濾bef它開始返回第一個項目(查詢計劃使用散列抗連接)

我們需要此查詢以非常快的速度返回前幾個項目 - 理想情況下返回500ms內的第一個項目。這意味着它不能遍歷items並過濾掉itemsProcessed中的那些。因此,我們需要做的加盟itemsitemsProcessed否定指標的某些方面(我們已經在蒙戈做到了這一點,但甲骨文似乎好好嘗試一下才能夠做類似的事情)

這可能與甲骨文?

+0

如果這能給出更好的結果,你可以試試嗎? 'AND ID IN(SELECT item FROM itemsProcessed WHERE processor> 2)'。如果你的'processor'永遠不是'NULL',它應該返回相同的結果,但是不用'NOT'表示,在某些情況下可能更好地使用索引 –

+0

你的外鍵索引 - 是你說你有一個「相關」索引,或者你只索引了'processor'?它們是什麼類型的索引?執行計劃顯示了什麼?你是否試過使用'not exists'而不是'rownum'停止鍵,如果你只想要前幾個未處理的rows? –

+0

查詢所需的時間還取決於您在<對項目的附加查詢>中所做的操作。是否在表上使用索引? –

回答

0

IMO這是一個設計問題。當您試圖包含尚未處理的項目時,您正試圖排除已處理的項目。已處理的物品清單將不斷增加;待處理項目的清單仍然很小。我建議您創建一個要處理的項目表,然後將它內部連接到查詢,並在ITEMS_TO_BE_PROCESSED表處理它們時刪除項目,而不是處理已處理的項目表(項目處理)。

祝你好運。

+0

這也是我的首選解決方案,但不幸的是,每個項目創建時都不知道處理器列表。 – thecoop

1

你可以嘗試你查詢

SELECT /*+ first_rows (10) */... FROM items i ... 

還是儘量先選擇未處理項目添加/*+ first_rows */暗示,比做<additional queries on items>

with i_to_process AS 
(
    SELECT item FROM items 
    minus 
    SELECT item FROM itemsProcessed WHERE processor IN (1, 2) 
) 
select * from i_to_process 
where 
<additional queries on items> 
0

根據表的更新頻率,你可以創建itemsNotProcessed的物化視圖。處理將事先完成。你也可以反正規化一點,並向項目表添加一個處理過的標誌,並在標誌上添加一個位圖索引。