我想提高我已經寫了一個概念證明業績和我有沒有運氣。我認爲這種做法可能有缺陷,但我正在努力尋找另一種解決方案。我已經涵蓋了我可以找到的所有Ask Tom文章和論壇帖子。的Oracle SQL層次查詢:層次扁平化和執行聚集
我們正在運行Oracle 10g R2。
我們安排在一個層次結構的項目。數量是根據關係定義的。在層次結構中有兩種類型的對象:作爲邏輯分組的組件和表示實際項目的項目。所以如果我們代表一個完整的工具集,我們將有一個代表整個工具集的根,以及一個代表實際工具的葉。所以:
工具集 - >螺絲刀 - >平頭螺絲刀 - >小扁頭螺絲刀
可以在層次結構中重複使用的組件,如項目。
我需要扁平化層級,所以一個項目的每個實例都有一個行和數量。任何關係可以有一個數量> = 1。爲了得到一個項目的數量,我們需要從根到葉子的所有關係中得到數量的乘積。
我的解決方案的工作,但它不能很好地擴展。針對實際數據運行需要大約8分鐘時間來生成6000多行,並且我們擁有可產生50k +行的層次結構。理想的情況是在10秒以內完成,但我知道這是......樂觀;)
我的解決方案和簡化的數據集如下。任何反饋將非常感謝!
CREATE TABLE ITEMHIER
(
PARENT VARCHAR2(30 BYTE),
CHILD VARCHAR2(30 BYTE),
QUANTITY NUMBER(15,2),
ISLEAF NUMBER
);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY005','ITEM001',2,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY005','ITEM002',1,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY005','ITEM003',5,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY006','ITEM002',10,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY006','ITEM004',3,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY007','ITEM005',12,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY007','ITEM006',1,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY008','ITEM006',2,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY008','ITEM005',5,1);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY002','ASSY005',2,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY002','ASSY007',1,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY003','ASSY006',3,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY003','ASSY008',2,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY004','ASSY007',1,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY004','ASSY005',3,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY004','ASSY006',2,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY001','ASSY002',1,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY001','ASSY003',2,0);
INSERT INTO ITEMHIER (PARENT, CHILD, QUANTITY, ISLEAF) VALUES ('ASSY001','ASSY004',1,0);
COMMIT;
/
CREATE OR REPLACE FUNCTION GETQTY(P_NAVPATH IN VARCHAR2,
P_STARTWITH IN VARCHAR2) RETURN INTEGER AS
R_QTY INTEGER;
BEGIN
SELECT EXP(SUM(LN(QUANTITY)))
INTO R_QTY
FROM (
SELECT QUANTITY, SYS_CONNECT_BY_PATH(CHILD,'/') NAV_PATH
FROM ITEMHIER
START WITH PARENT = P_STARTWITH
CONNECT BY PRIOR CHILD = PARENT
)
WHERE INSTR(P_NAVPATH, NAV_PATH) = 1;
RETURN R_QTY;
END;
/
SELECT 'ASSY001' || SYS_CONNECT_BY_PATH(CHILD,'/') NAV_PATH,
GETQTY(SYS_CONNECT_BY_PATH(CHILD,'/'), 'ASSY001') QTY,
CHILD
FROM ITEMHIER
WHERE ISLEAF = 1
START WITH PARENT = 'ASSY001'
CONNECT BY PRIOR CHILD = PARENT;
----編輯
使用WITH
條款我是能夠削減處理時間約1/2,這是一個很大的收穫!任何其他想法?
with
h as (
select sys_connect_by_path(child,'/') navpath,
child,
quantity qty,
isleaf
from itemhier
start with parent = 'ASSY001'
connect by prior child = parent
)
select h1.navpath,
h1.child,
(SELECT exp(sum(ln(h2.qty)))
FROM h h2
WHERE instr(h1.navpath, h2.navpath) = 1) qty
from h h1
where isleaf = 1
EDIT 2
jonearles建議使用SYS_CONNECT_BY_PATH構建算術表達式,然後使用PL/SQL來評估它似乎是要走的路。針對我最大的數據集運行,我能夠在55秒內產生77k行輸出。
我也試圖使用並行性,但正如他指出的那樣,幾乎沒有性能提升。
索引'PARENT'可能會有很大的幫助。您的示例數據非常有用,並且比大多數人發佈的數據好得多,但爲了診斷性能問題,它將有助於獲得更多數據。例如,我用這樣的腳本來創建一個更大的數據集:'開始我在1 .. 100000循環插入ITEMHIER(父母,兒童,數量,ISLEAF)值('ASSY005'|| lpad( ',6,'0'),'ITEM001'|| lpad(i,6,'0'),2,1); ...'。 但我不確定這是否真正代表您的數據。 –
謝謝......我試圖徹底,答案只有問題:)表已索引得很好,父母是其中的一個指標。我非常有信心,索引部門沒有太多的收穫。 – tac0