向索引聚簇表載入資料極講究順序。錯誤的載入方式會導致同一叢集鍵的資料分散在不同 Block,完全喪失聚簇優勢。本文透過實測案例,示範正確與錯誤的載入策略差異。
為放大效果,先在 EMP 表新增 CHAR(1000) 欄位,使單筆記錄遠超 1024 位元組叢集 SIZE 設定,強制產生鏈結區塊:
ALTER TABLE emp ADD data CHAR(1000);
並先建立叢集索引、停用外鍵約束、截斷叢集以確保乾淨環境:
CREATE INDEX emp_dept_cluster_idx ON CLUSTER emp_dept_cluster;
ALTER TABLE emp DISABLE CONSTRAINT emp_fk;
TRUNCATE CLUSTER emp_dept_cluster;
ALTER TABLE emp ENABLE CONSTRAINT emp_fk;
INSERT INTO dept SELECT * FROM scott.dept;
INSERT INTO emp SELECT emp.*, '*' FROM scott.emp;
驗證查詢:
SELECT dept_blk, emp_blk,
CASE WHEN dept_blk <> emp_blk THEN '*' END flag, deptno
FROM (
SELECT DBMS_ROWID.ROWID_BLOCK_NUMBER(dept.ROWID) dept_blk,
DBMS_ROWID.ROWID_BLOCK_NUMBER(emp.ROWID) emp_blk,
dept.deptno
FROM emp, dept
WHERE emp.deptno = dept.deptno
) ORDER BY deptno;
結果顯示大部分 DEPT_BLK (85) 與 EMP_BLK (86, 87) 不同,標記 *,證明資料未共存同一 Block。
核心原則:**同一 deptno 的 DEPT 與 EMP 資料必須連續寫入**,讓 Oracle 將其放入同一 Block。範例程式碼:
BEGIN
FOR x IN (SELECT * FROM scott.dept) LOOP
INSERT INTO dept VALUES (x.deptno, x.dname, x.loc);
INSERT INTO emp
SELECT emp.*, '*' FROM scott.emp
WHERE deptno = x.deptno;
END LOOP;
COMMIT;
END;
/
此寫法確保每個部門的主檔與明細檔在同一迴圈內寫入,Oracle 會嘗試將其置於同一 Block(或鏈結 Block),最大化聚簇效益。
SIZE 設定,會產生鏈結區塊;此時 SIZE 應依實際平均記錄大小估算,避免過度鏈結。上述驗證查詢可作為標準檢核腳本,定期檢查關鍵聚簇表的 Block 共存率,確保資料物理分佈符合預期。