真實生產系統 BSS_ORG 表 (5,739 筆),測試環境 Oracle 9i/10g/11g 一致:
BSS_ORG_ID NOT NULL NUMBER(9) -- PK, 5739 distinct
NAME NOT NULL VARCHAR2(64) -- 5034 distinct
BSS_PARENT_ORG_ID NUMBER(9) -- 905 distinct, 形成樹狀結構
BSS_ORG_LEVEL_ID NOT NULL NUMBER(3) -- 6 distinct
STATE NOT NULL VARCHAR2(3) -- 2 distinct
SELECT * FROM bss_org t
START WITH bss_org_id = 832044754
CONNECT BY bss_parent_org_id = PRIOR bss_org_id;
SELECT * FROM bss_org t
START WITH bss_org_id = 832044754 -- 同一根節點
CONNECT BY bss_parent_org_id = PRIOR bss_org_id;
現象:同一 SQL 結構,不同 START WITH 值,實際返回行數差異巨大,但優化器給出相同估算 (5739 或 6),完全無視 START WITH 過濾效果。
| Id | Operation | Name | Rows |
| 1 | CONNECT BY WITH FILTERING | | |
| 2 | TABLE ACCESS BY INDEX ROWID | BSS_ORG | |
| 3 | INDEX UNIQUE SCAN | PK_BSS_ORG| 1 |
| 4 | HASH JOIN | | |
| 5 | CONNECT BY PUMP | | |
| 6 | TABLE ACCESS FULL | BSS_ORG | 5739 |
| 7 | TABLE ACCESS FULL | BSS_ORG | 5739 |
估算 5739 行 → 選擇 HASH JOIN → 效能極差
CONNECT BY NO FILTERING,估算變 6 行 → 效能大幅提升
SELECT /*+ INDEX(t idx_bss_parent_org_id) */ * FROM bss_org t
START WITH bss_org_id = :root_id
CONNECT BY bss_parent_org_id = PRIOR bss_org_id;
WITH tree_path AS (
SELECT /*+ MATERIALIZE */ * FROM bss_org
START WITH bss_org_id = :root_id
CONNECT BY bss_parent_org_id = PRIOR bss_org_id
)
SELECT * FROM tree_path WHERE ...; -- 後續查詢使用物化結果
WITH RECURSIVE org_tree (org_id, parent_id, lvl) AS (
SELECT bss_org_id, bss_parent_org_id, 1 FROM bss_org WHERE bss_org_id = :root_id
UNION ALL
SELECT c.bss_org_id, c.bss_parent_org_id, p.lvl + 1
FROM bss_org c JOIN org_tree p ON c.bss_parent_org_id = p.org_id
)
SELECT * FROM org_tree;
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'BSS_ORG',
METHOD_OPT => 'FOR COLUMNS SIZE 254 BSS_PARENT_ORG_ID');
SELECT /*+ CARDINALITY(t 10) */ * FROM bss_org t
START WITH bss_org_id = :root_id
CONNECT BY bss_parent_org_id = PRIOR bss_org_id;