2016-10-17 250 views
2

創建集合類型:快速搜索

CREATE TABLE test1 (
     num NUMBER, 
     tagged nums_list 
) 
NESTED TABLE tagged STORE AS mytest_tagged_table; 

插入1個百萬行表:

CREATE TYPE nums_list AS TABLE OF NUMBER; 

與集合類型(嵌套表列)的列創建表

DECLARE 
    tagg_value nums_list := nums_list(3,4,5); 
BEGIN 
    for i in 1..1000000 loop 
      if i = 600000 then 
       tagg_value := nums_list(7,8); 
      end if; 

      INSERT INTO test1 
      (num, tagged) 
      VALUES 
      (i, tagg_value); 
    end loop; 
END; 

然後運行查詢搜索集合類型中的元素:

select count(*) from test1 where 8 member of tagged; 

該查詢運行緩慢,大約7-8秒爲執行時間。

問題:如何加快執行時間?可能是索引?但如何使用嵌套表列的索引我沒有得到。

P.S.我嘗試使用循環檢查PL/SQL塊中的每一行,使用遊標,然後將結果作爲流水線表函數返回,但這比直接查詢更慢。

+0

正如你寫過你的例子,我認爲600,000以上的所有行將在列表中的數字8。這意味着,您的查詢將返回400,000(1,000,000行之中)。嵌套表格與否,這不是索引將幫助很大的查詢類型。這是你的意圖在這個例子中,有很多行滿足查詢? –

+1

@Mthethew - 確切的說是400,001行返回這個查詢。這是如此大的數據嗎? – RIKI

+1

本身並不是說它「大」。這是它佔表格總行數的很大一部分。在這種情況下,讀取整個表(即「全表掃描」)來執行搜索會更有效,而不是400,000個索引查找。完整掃描可以在單個I/O中讀取多個表格塊,而索引查找則需要每行__行3至4個I/O。如此狹窄的表格,全表掃描可能需要少於100,000次I/O(粗略猜測),而嵌套循環連接索引可能需要超過一百萬個I/O。 –

回答

3

如果您從您的例子此查詢執行EXPLAIN PLAN

select count(*) from test1 where 8 member of tagged; 

...你會看到,甲骨文或許使用上mytest_tagged_table一個(系統生成)的索引來幫助性能。它仍然需要這麼長時間的原因是,與僅僅讀整個表相比,400,000個索引查找實際上是更少的

所以,問題不是「我如何讓Oracle使用嵌套表的索引」?這是我怎麼能得到Oracle 而不是

由於您的tagged列表看起來很小,因此您可以使用VARRAY。這些可以以內聯方式存儲以獲得更好的性能,但相關語法不夠清晰。

這裏就是你們的榜樣,修改VARRAY

CREATE NONEDITIONABLE TYPE nums_varray AS VARRAY(10) OF NUMBER; 

CREATE TABLE test2 (
     num NUMBER, 
     tagged nums_varray 
); 

INSERT INTO test2 
SELECT rownum, 
     case when rownum < 600000 then new nums_varray(3,4,5) else new nums_varray(7,8) end 
FROM dual 
connect by rownum <= 1000000; 


select count(*) from test2 
where exists ( 
    SELECT '8 in list' 
    FROM TABLE(tagged) 
    WHERE column_value = 8); 

在我的系統,這個只需要3600緩衝獲得運行 - 而不是2.1億緩衝獲取所需的示例查詢。相應地,它也運行得更快。

VARRAYS不是直接等同於嵌套表,他們帶有警告。但是,根據你的例子,他們可能是你正在尋找的東西。