私はすでに書いた概念実証のためにパフォーマンスを改善しようとしていますが、運がありません。このアプローチにはおそらく欠陥があると思いますが、別の解決策を見つけるのに苦労しています。私が見つけることができるすべてのAskTomの記事とフォーラムの投稿をカバーしました。
Oracle10gR2を実行しています。
アイテムは階層構造で配置されています。数量は関係で定義されます。階層内のオブジェクトには、論理グループであるアセンブリと、実際のアイテムを表すアイテムの2種類があります。したがって、完全なツールセットを表す場合、ツールセット全体を表すルートと、実際のツールを表すリーフがあります。それで:
ツールセット->ドライバー->マイナスドライバー->小型マイナスドライバー
アセンブリは、アイテムと同様に、階層で再利用できます。
アイテムの各インスタンスに行と数量が含まれるように、階層をフラット化する必要があります。どの関係も数量>=1にすることができます。アイテムの数量を取得するには、ルートからリーフまでのすべての関係から数量の積を取得する必要があります。
私のソリューションは機能しますが、拡張性が高くありません。実際のデータに対して実行すると、6000以上の行を生成するのに約8分かかり、5万以上の行を生成する階層があります。理想的にはこれは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
編集2
sys_connect_by_pathを使用して算術式を作成し、PL / SQLを使用してそれを評価するというjonearlesの提案は、進むべき道のようです。最大のデータセットに対して実行すると、55秒で77k行の出力を生成できました。
私も並列処理を使用しようとしましたが、彼が指摘したように、パフォーマンスの向上はほとんどまたはまったくありませんでした。