Oracle8i 中引入的查詢重寫特性在數(shù)據(jù)倉(cāng)庫(kù)開發(fā)人員和 DBA 中轟動(dòng)一時(shí)。從本質(zhì)上而言,它將用戶查詢重寫為從 MV 而非表中進(jìn)行選擇以利用現(xiàn)成的摘要。例如,請(qǐng)考慮以下一家大型連鎖酒店的數(shù)據(jù)庫(kù)中的三個(gè)表。 SQL> DESC HOTELS Name Null?Type ----------------------------------------- -------- ------------- HOTEL_ID NOT NULL NUMBER(10) CITY VARCHAR2(20) STATE CHAR(2) MANAGER_NAME VARCHAR2(20) RATE_CLASS CHAR(2) SQL> DESC RESERVATIONS Name Null?Type ----------------------------------------- -------- ------------- RESV_ID NOT NULL NUMBER(10) HOTEL_ID NUMBER(10) CUST_NAME VARCHAR2(20) START_DATE DATE END_DATE DATE RATE NUMBER(10) SQL> DESC TRANS Name Null?Type ----------------------------------------- -------- ------------- TRANS_ID NOT NULL NUMBER(10) RESV_ID NOT NULL NUMBER(10) TRANS_DATE DATE ACTUAL_RATE NUMBER(10) 表 HOTELS 保存酒店的相關(guān)信息。當(dāng)顧客預(yù)訂酒店時(shí),將在表 RESERVATIONS(包含房間價(jià)格報(bào)價(jià))中創(chuàng)建一個(gè)記錄。當(dāng)顧客在酒店結(jié)帳時(shí),將在另一個(gè)表 TRANS 中記錄現(xiàn)金交易。
但在結(jié)帳前,酒店可能決定根據(jù)訂房情況、升級(jí)、優(yōu)惠等因素向顧客提供不同的房?jī)r(jià)。因此,最終的房?jī)r(jià)可能與預(yù)訂時(shí)的報(bào)價(jià)不同,而且可以天天都各不相同。為正確記錄這些價(jià)格變化,表 TRANS 有一行專門用來(lái)保存天天的房?jī)r(jià)信息。
為縮短查詢響應(yīng)時(shí)間,您可能決定根據(jù)用戶發(fā)出的不同查詢構(gòu)建 MV,如: create materialized view mv_hotel_resv refresh complete enable query rewrite as select city, resv_id, cust_name from hotels h, reservations r where r.hotel_id = h.hotel_id; 和 create materialized view mv_actual_sales refresh complete enable query rewrite as select resv_id, sum(actual_rate) from trans group by resv_id; 因此,假如設(shè)置了某些參數(shù)(如 query_rewrite_enabled = true),則類似如下所示的查詢 select city, cust_name from hotels h, reservations r where r.hotel_id = h.hotel_id; 將重寫為 select city, cust_name from mv_hotel_resv; 您可以通過(guò)運(yùn)行該查詢并啟用自動(dòng)跟蹤來(lái)確認(rèn) MV。 SQL> set autot traceonly eXPlain SQL> select city, cust_name 2> from hotels h, reservations r 3> where r.hotel_id = h.hotel_id; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=80 Bytes=2480) 1 0 MAT_VIEW access (FULL) OF 'MV_HOTEL_RESV' (MAT_VIEW) (Cost=3 Card=80 Bytes=2480)
我們來(lái)采用一個(gè)不同的查詢。假如要查明每個(gè)城市的實(shí)際銷售額,則將發(fā)出 select city, sum(actual_rate) from hotels h, reservations r, trans t where t.resv_id = r.resv_id and r.hotel_id = h.hotel_id group by city; 注重此查詢結(jié)構(gòu):從 MV_ACTUAL_SALES 中,您可以獲得 RESV_ID 和預(yù)訂的總銷售額。從 MV_HOTEL_RESV 中,您可以獲得 CITY 和 RESV_ID。
您唯一的救濟(jì)方法就是將最大值分區(qū)分割為兩個(gè)部分:一個(gè)用于新月份的分區(qū)和一個(gè)新的最大值分區(qū)。但將該方法用于已分區(qū)的按索引組織的表時(shí)將碰到一個(gè)小問(wèn)題。這種情況下,將先創(chuàng)建物理分區(qū),并將行從最大值分區(qū)移動(dòng)到該分區(qū),這樣將消耗 I/O 和 CPU 周期。
將 LONG 列轉(zhuǎn)換為 LOB 列時(shí),您很希望獲得高性能;您需要使該過(guò)程盡可能地快。假如將表進(jìn)行了分區(qū),則該過(guò)程將跨分區(qū)并行執(zhí)行。但假如未將表進(jìn)行分區(qū),則該過(guò)程將串行執(zhí)行,從而可能持續(xù)很長(zhǎng)時(shí)間。
我們來(lái)看一下它的工作原理。以下是 TRANS 表的結(jié)構(gòu): SQL> desc trans Name Null?Type --------------------------------- -------- ------------------------- TRANS_ID NUMBER TRANS_DATE DATE TXN_TYPE VARCHAR2(1) ACC_NO NUMBER TX_AMT NUMBER(12,2) STATUS 該表已經(jīng)按如下所示進(jìn)行了分區(qū): partition by range (trans_date) ( partition y03q1 values less than (to_date('04/01/2003','mm/dd/yyyy')), partition y03q2 values less than (to_date('07/01/2003','mm/dd/yyyy')), partition y03q3 values less than (to_date('10/01/2003','mm/dd/yyyy')), partition y03q4 values less than (to_date('01/01/2004','mm/dd/yyyy')), partition y04q1 values less than (to_date('04/01/2004','mm/dd/yyyy')), partition y04q2 values less than (to_date('07/01/2004','mm/dd/yyyy')), partition y04q3 values less than (to_date('10/01/2004','mm/dd/yyyy')), partition y04q4 values less than (to_date('01/01/2005','mm/dd/yyyy')), partition y05q1 values less than (to_date('04/01/2005','mm/dd/yyyy')), partition y05q2 values less than (to_date('07/01/2005','mm/dd/yyyy')) ) 在某個(gè)時(shí)刻,您決定將分區(qū) Y03Q2 移動(dòng)到另一個(gè)表空間 (TRANSY03Q2),該表空間可能位于一個(gè)不同類型的磁盤(一個(gè)慢一點(diǎn)、便宜一點(diǎn)的磁盤)上。為此,請(qǐng)首先確認(rèn)您可以聯(lián)機(jī)重新定義該表: begin dbms_redefinition.can_redef_table( uname => 'ARUP', tname => 'TRANS', options_flag => dbms_redefinition.cons_use_rowid, part_name => 'Y03Q2'); end; / 此處沒(méi)有輸出,因此您確認(rèn)可以聯(lián)機(jī)重新定義該表。接下來(lái),創(chuàng)建一個(gè)臨時(shí)表保存該分區(qū)的數(shù)據(jù): create table trans_temp ( trans_id number, trans_date date, txn_type varchar2(1), acc_no number, tx_amt number(12,2), status varchar2(1) ) tablespace transy03q2 / 請(qǐng)注重,由于表 TRANS 進(jìn)行了范圍分區(qū),因此您已經(jīng)將該表定義為未分區(qū)表。該表在所需的表空間 TRANSY03Q2 中創(chuàng)建。假如表 TRANS 包含一些本地索引,則表示您已經(jīng)對(duì)表 TRANS_TEMP 創(chuàng)建了這些索引(當(dāng)然是創(chuàng)建為未分區(qū)索引)。
要演示這個(gè)新行為,您可以使用 10046 跟蹤跟蹤該會(huì)話。 alter session set events '10046 trace name context forever, level 12'; 然后,刪除該表。假如查看跟蹤文件,則將看到分區(qū)表刪除的代碼: delete from tabpart$ where bo# = :1 delete from partobj$ where obj#=:1 delete from partcol$ where obj#=:1 delete from subpartcol$ where obj#=:1 請(qǐng)注重,分區(qū)是按順序刪除的。該方法最大限度地降低了刪除過(guò)程中的資源使用率并增強(qiáng)了性能。