已閱讀5頁,還剩46頁未讀, 繼續(xù)免費閱讀
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
Oracle SQL 性能調整 1. 選用適合的 ORACLE 優(yōu)化器 ORACLE 的優(yōu)化器共有 3 種 : a. RULE (基于規(guī)則 ) b. COST (基于成本 ) c. CHOOSE (選擇性 ) 設置缺省的優(yōu)化器 ,可以通過對 init.ora文件中 OPTIMIZER_MODE參數(shù)的各種聲明 ,如 RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你當然也在 SQL句級或是會話 (session)級對其進行覆蓋 . 為了使用基于成本的優(yōu)化器 (CBO, Cost-Based Optimizer) , 你必須經常運行 analyze 命令 ,以增加數(shù)據(jù)庫中的對象統(tǒng)計信息 (object statistics)的準確性 . 如果數(shù)據(jù)庫的優(yōu)化器模式設置為選擇性 (CHOOSE),那么實際的優(yōu)化器模式將和是否運行過analyze 命令有關 . 如果 table 已經被 analyze 過 , 優(yōu)化器模式將自動成為 CBO , 反之 ,數(shù)據(jù)庫將采用 RULE 形式的優(yōu)化器 . 在缺省情況下 ,ORACLE采用 CHOOSE優(yōu)化器 , 為了避免那些不必要的全表掃描 (full table scan) , 你必須盡 量避免使用 CHOOSE 優(yōu)化器 ,而直接采用基于規(guī)則或者基于成本的優(yōu)化器 . 2.訪問 Table 的方式 ORACLE 采用兩種訪問表中記錄的方式 : a.全表掃描 全表掃描就是順序地訪問表中每條記錄 . ORACLE 采用一次讀入多個數(shù)據(jù)塊 (database block)的方式優(yōu)化全表掃描 . b.通過 ROWID 訪問表 你可以采用基于 ROWID 的訪問方式情況 ,提高訪問表的效率 , , ROWID 包含了表中記錄的物理位置信息 .ORACLE 采用索引 (INDEX)實現(xiàn)了數(shù)據(jù)和存放數(shù)據(jù)的物理位置 (ROWID)之間的聯(lián)系 . 通常索引提供了快速訪問 ROWID的方法 ,因此那些基于索引列的查詢就可以得到性能上的提高 . 3.共享 SQL 語句 為了不重復解析相同的 SQL 語句 ,在第一次解析之后 , ORACLE 將 SQL 語句存放在內存中 .這塊位于系統(tǒng)全局區(qū)域 SGA(system global area)的共享池 (shared buffer pool)中的內存可以被所有的數(shù)據(jù)庫用戶共享 . 因此 ,當你執(zhí)行一個 SQL 語句 (有時被稱為一個游標 )時 ,如果它和之前的執(zhí)行過的語句完全相同 , ORACLE 就能很快獲得已經被解析的語句以及最好的 執(zhí)行路徑 . ORACLE 的這個功能大大地提高了 SQL 的執(zhí)行性能并節(jié)省了內存的使用 . 可惜的是 ORACLE只對簡單的表提供高速緩沖 (cache buffering) ,這個功能并不適用于多表連接查詢 . 數(shù)據(jù)庫管理員必須在 init.ora中為這個區(qū)域設置合適的參數(shù) ,當這個內存區(qū)域越大 ,就可以保留更多的語句 ,當然被共享的可能性也就越大了 . 當你向 ORACLE 提交一個 SQL 語句 ,ORACLE 會首先在這塊內存中查找相同的語句 .這里需要注明的是 ,ORACLE 對兩者采取的是一種嚴格匹配 ,要達成共享 ,SQL 語句 必須完全相同 (包括空格 ,換行等 ). 共享的語句必須滿足三個條件 : A.字符級的比較 : 當前被執(zhí)行的語句和共享池中的語句必須完全相同 . 例如 : SELECT * FROM EMP; 和下列每一個都不同 SELECT * from EMP; Select * From Emp; SELECT * FROM EMP; B. 兩個語句所指的對象必須完全相同 : 例如 : 用戶 對象名 如何訪問 Jack sal_limit private synonym Work_city public synonym Plant_detail public synonym Jill sal_limit private synonym Work_city public synonym Plant_detail table owner 考慮一下下列 SQL語句能否在這兩個用戶之間共享 . SQL 能否共享 原因 select max(sal_cap) from sal_limit; 不能 每個用戶都有一個 private synonym - sal_limit , 它們是不同的對象 select count(*0 from work_city where sdesc like NEW%; 能 兩個用戶訪問相同的對象 public synonym - work_city select a.sdesc,b.location from work_city a , plant_detail b where a.city_id = b.city_id 不能 用戶 jack 通過 private synonym訪問 plant_detail 而 jill 是表的所有者 ,對象不同 . C. 兩個 SQL 語句中必須使用相同的名字的綁定變量 (bind variables) 例如: 第一組的兩個 SQL 語句是相同的 (可以共享 ),而第二組中的兩個語句是不同的 (即使在運行時 ,賦于不同的綁定變量相同的值 ) a. select pin , name from people where pin = :blk1.pin; select pin , name from people where pin = :blk1.pin; b. select pin , name from people where pin = :blk1.ot_ind; select pin , name from people where pin = :blk1.ov_ind; 4. 選擇最有效率的表名順序 (只在基于規(guī)則的優(yōu)化器中有效 ) ORACLE 的解析器按照從右到左的順序處理 FROM 子句中的表名 ,因此 FROM 子句中寫在最后的表 (基礎表 driving table)將被最先處理 . 在 FROM子句中包含多個表的情況下 ,你必須選擇記錄條數(shù)最少的表作為基礎表 .當 ORACLE 處理多個表時 , 會運用排序及合并的方式連接它們 .首先 ,掃描第一個表 (FROM 子句中最后的那個表 )并對記錄進行派序 ,然后掃描第二個表 (FROM 子句中最后第二個表 ),最后將所有從第二個表中檢索出的記錄與第一個表中合適記錄進行合并 . 例如 : 表 TAB1 16,384 條記錄 表 TAB2 1 條記錄 選擇 TAB2 作為基礎表 (最好的方法 ) select count(*) from tab1,tab2 執(zhí)行時間 0.96 秒 選擇 TAB2 作為基礎表 (不佳的方法 ) select count(*) from tab2,tab1 執(zhí)行時間 26.09 秒 如果有 3 個以上的表連接查詢 , 那就需要選擇交叉表 (intersection table)作為基礎表 , 交叉表是指那個被其他表所引用的表 . 例如 : EMP 表描述了 LOCATION 表和 CATEGORY 表的交集 . SELECT * FROM LOCATION L , CATEGORY C, EMP E WHERE E.EMP_NO BETWEEN 1000 AND 2000 AND E.CAT_NO = C.CAT_NO AND E.LOCN = L.LOCN 將比下列 SQL 更有效率 SELECT * FROM EMP E , LOCATION L , CATEGORY C WHERE E.CAT_NO = C.CAT_NO AND E.LOCN = L.LOCN AND E.EMP_NO BETWEEN 1000 AND 2000 5.WHERE 子句中的連接順序 ORACLE 采用自下而上的順序解析 WHERE 子句 ,根據(jù)這個原理 ,表之間的連接必須寫在其他 WHERE 條件之前 , 那些可以過濾掉最大數(shù)量記錄的條件必須寫在 WHERE 子句的末尾 . 例如 : (低效 ,執(zhí)行時間 156.3 秒 ) SELECT FROM EMP E WHERE SAL 50000 AND JOB = MANAGER AND 25 50000 AND JOB = MANAGER ; 6.SELECT 子句中避免使用 * 當你想在 SELECT 子句中列出所有的 COLUMN 時 ,使用動態(tài) SQL 列引用 * 是一個方便的方法 .不幸的是 ,這是一個 非常低效的方法 . 實際上 ,ORACLE 在解析的過程中 , 會將 * 依次轉換成所有的列名 , 這個工作是通過查詢數(shù)據(jù)字典完成的 , 這意味著將耗費更多的時間 . 7.減少訪問數(shù)據(jù)庫的次數(shù) 當執(zhí)行每條 SQL語句時 , ORACLE在內部執(zhí)行了許多工作 : 解析 SQL語句 , 估算索引的利用率 , 綁定變量 , 讀數(shù)據(jù)塊等等 . 由此可見 , 減少訪問數(shù)據(jù)庫的次數(shù) , 就能實際上減少 ORACLE的工作量 . 例如 ,以下有三種方法可以檢索出雇員號等于 0342 或 0291 的職員 . 方法 1 (最低效 ) SELECT EMP_NAME , SALARY , GRADE FROM EMP WHERE EMP_NO = 342; SELECT EMP_NAME , SALARY , GRADE FROM EMP WHERE EMP_NO = 291; 方法 2 (次低效 ) DECLARE CURSOR C1 (E_NO NUMBER) IS SELECT EMP_NAME,SALARY,GRADE FROM EMP WHERE EMP_NO = E_NO; BEGIN OPEN C1(342); FETCH C1 INTO ,.,. ; . OPEN C1(291); FETCH C1 INTO ,.,. ; CLOSE C1; END; 方法 3 (高效 ) SELECT A.EMP_NAME , A.SALARY , A.GRADE, B.EMP_NAME , B.SALARY , B.GRADE FROM EMP A,EMP B WHERE A.EMP_NO = 342 AND B.EMP_NO = 291; 注意 : 在 SQL*Plus , SQL*Forms和 Pro*C中重新設置 ARRAYSIZE參數(shù) , 可以增加每次數(shù)據(jù)庫訪問的檢索數(shù)據(jù)量 ,建議值為 200 8.使用 DECODE 函數(shù)來減少處理時間 使用 DECODE 函數(shù)可以避免重復掃描相同記錄或重復連接相同的表 . 例如 : SELECT COUNT(*), SUM(SAL) FROM EMP WHERE DEPT_NO = 0020 AND ENAME LIKE SMITH% ; SELECT COUNT(*), SUM(SAL) FROM EMP WHERE DEPT_NO = 0030 AND ENAME LIKE SMITH% ; 你可以用 DECODE 函數(shù)高效地得到相同結果 SELECT COUNT(DECODE(DEPT_NO,0020, X ,NULL) D0020_COUNT, COUNT(DECODE(DEPT_NO,0030, X ,NULL) D0030_COUNT, SUM(DECODE(DEPT_NO,0020,SAL,NULL) D0020_SAL, SUM(DECODE(DEPT_NO,0030,SAL,NULL) D0030_SAL FROM EMP WHERE ENAME LIKE SMITH% ; 類似的 ,DECODE 函數(shù)也可以運用于 GROUP BY 和 ORDER BY 子句中 . 9.整合簡單 ,無關聯(lián)的數(shù)據(jù) 庫訪問 如果你有幾個簡單的數(shù)據(jù)庫查詢語句 ,你可以把它們整合到一個查詢中 (即使它們之間沒有關系 ) 例如 : SELECT NAME FROM EMP WHERE EMP_NO = 1234; SELECT NAME FROM DPT WHERE DPT_NO = 10 ; SELECT NAME FROM CAT WHERE CAT_TYPE = RD ; 上面的 3 個查詢可以被合并成一個 : SELECT E.NAME , D.NAME , C.NAME FROM CAT C , DPT D , EMP E,DUAL X WHERE NVL( X ,X.DUMMY) = NVL( X ,E.ROWID(+) AND NVL( X ,X.DUMMY) = NVL( X ,D.ROWID(+) AND NVL( X ,X.DUMMY) = NVL( X ,C.ROWID(+) AND E.EMP_NO(+) = 1234 AND D.DEPT_NO(+) = 10 AND C.CAT_TYPE(+) = RD ; (譯者按 : 雖然采取這種方法 ,效率得到提高 ,但是程序的可讀性大大降低 ,所以讀者 還是要權衡之間的利弊 ) 10.刪除重復記錄 最高效的刪除重復記錄方法 ( 因為使用了 ROWID) DELETE FROM EMP E WHERE E.ROWID (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO); 11.用 TRUNCATE 替代 DELETE 當刪除表中的記錄時 ,在通常情況下 , 回滾段 (rollback segments ) 用 來存放可以被恢復的信息 . 如果你沒有 COMMIT事務 ,ORACLE會將數(shù)據(jù)恢復到刪除之前的狀態(tài) (準確地說是恢復到執(zhí)行刪除命令之前的狀況 ) 而當運用 TRUNCATE 時 , 回滾段不再存放任何可被恢復的信息 .當命令運行后 ,數(shù)據(jù)不能被恢復 .因此很少的資源被調用 ,執(zhí)行時間也會很短 . (譯者按 : TRUNCATE 只在刪除全表適用 ,TRUNCATE 是 DDL 不是 DML) 12.盡量多使用 COMMIT 只要有可能 ,在程序中盡量多使用 COMMIT, 這樣程序的性能得到提高 ,需求也會因為 COMMIT所釋放的資源而減少 : COMMIT 所釋放的資源 : a. 回滾段上用于恢復數(shù)據(jù)的信息 . b. 被程序語句獲得的鎖 c. redo log buffer 中的空間 d. ORACLE 為管理上述 3 種資源中的內部花費 (譯者按 : 在使用 COMMIT 時必須要注意到事務的完整性 ,現(xiàn)實中效率和事務完整性往往是魚和熊掌不可得兼 ) 13.計算記錄條數(shù) 和一般的觀點相反 , count(*) 比 count(1)稍快 , 當然如果可以通過索引檢索 ,對索引列的計數(shù)仍舊是最快的 . 例如 COUNT(EMPNO) (譯者按 : 在 CSDN 論壇中 ,曾經對此有過相當熱烈的討論 , 作者的觀點并不十分準確 ,通過實際的測試 ,上述三種方法并沒有顯著的性能差別 ) 14.用 Where 子句替換 HAVING 子句 避免使用 HAVING子句 , HAVING 只會在檢索出所有記錄之后才對結果集進行過濾 . 這個處理需要排序 ,總計等操作 . 如果能通過 WHERE 子句限制記錄的數(shù)目 ,那就能減少這方面的開銷 . 例如 : 低效 : SELECT REGION, AVG(LOG_SIZE) FROM LOCATION GROUP BY REGION HAVING REGION REGION != SYDNEY AND REGION != PERTH 高效 SELECT REGION, AVG(LOG_SIZE) FROM LOCATION WHERE REGION REGION != SYDNEY AND REGION != PERTH GROUP BY REGION (譯者按 : HAVING 中的條 件一般用于對一些集合函數(shù)的比較 ,如 COUNT() 等等 . 除此而外 ,一般的條件應該寫在 WHERE 子句中 ) 15.減少對表的查詢 在含有子查詢的 SQL 語句中 ,要特別注意減少對表的查詢 . 例如 : 低效 SELECT TAB_NAME FROM TABLES WHERE TAB_NAME = ( SELECT TAB_NAME FROM TAB_COLUMNS WHERE VERSION = 604) AND DB_VER= ( SELECT DB_VER FROM TAB_COLUMNS WHERE VERSION = 604) 高效 SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT TAB_NAME,DB_VER) FROM TAB_COLUMNS WHERE VERSION = 604) Update 多個 Column 例子 : 低效 : UPDATE EMP SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES), SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES) WHERE EMP_DEPT = 0020; 高效 : UPDATE EMP SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY) , MAX(SAL_RANGE) FROM EMP_CATEGORIES) WHERE EMP_DEPT = 0020; 16.通過內 部函數(shù)提高 SQL 效率 . SELECT H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC,COUNT(*) FROM HISTORY_TYPE T,EMP E,EMP_HISTORY H WHERE H.EMPNO = E.EMPNO AND H.HIST_TYPE = T.HIST_TYPE GROUP BY H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC; 通過調用下面的函數(shù)可以提高效率 . FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN VARCHAR2 AS TDESC VARCHAR2(30); CURSOR C1 IS SELECT TYPE_DESC FROM HISTORY_TYPE WHERE HIST_TYPE = TYP; BEGIN OPEN C1; FETCH C1 INTO TDESC; CLOSE C1; RETURN (NVL(TDESC, ? ); END; FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN VARCHAR2 AS ENAME VARCHAR2(30); CURSOR C1 IS SELECT ENAME FROM EMP WHERE EMPNO=EMP; BEGIN OPEN C1; FETCH C1 INTO ENAME; CLOSE C1; RETURN (NVL(ENAME, ? ); END; SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO), H.HIST_TYPE,LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT(*) FROM EMP_HISTORY H GROUP BY H.EMPNO , H.HIST_TYPE; (譯者按 : 經常在論壇中看到如 能不能用一個 SQL 寫出 . 的貼子 , 殊不知復雜的 SQL 往往犧牲了執(zhí)行效率 . 能夠掌握上面的運用函數(shù)解決問題的方法在實際工作中是非常有意義的 ) 17.使用表的別名 (Alias) 當在 SQL 語句中連接多個表時 , 請使用表的別名并把別名前綴于每個 Column 上 .這樣一來 ,就可以減少解析的時間并減少那些由 Column 歧義引起的語法錯誤 . (譯者注 : Column歧義指的是由于 SQL中不同的表具有相同的 Column名 ,當 SQL語句中出現(xiàn)這個Column 時 ,SQL 解析器無法判斷這個 Column 的歸屬 ) 18.用 EXISTS 替代 IN 在許多基于基礎表的查詢中 ,為了滿足一個條件 ,往往需要對另一個表進行聯(lián)接 .在這種情況下 , 使用 EXISTS(或 NOT EXISTS)通常將提高查詢的效率 . 低效 : SELECT * FROM EMP (基礎表 ) WHERE EMPNO 0 AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = MELB ) 高效 : SELECT * FROM EMP (基礎表 ) WHERE EMPNO 0 AND EXISTS (SELECT X FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = MELB ) (譯者按 : 相對來說 ,用 NOT EXISTS 替換 NOT IN 將更顯著地提高效率 ,下一節(jié)中將指出 ) 19.用 NOT EXISTS 替代 NOT IN 在子查詢中 ,NOT IN 子句將執(zhí)行一個內部的排序和合并 . 無論在哪種情況下 ,NOT IN 都是最低效的 (因為它對子查詢中的表執(zhí)行了一個全表遍歷 ). 為了避免使用 NOT IN ,我們可以把它改寫成外連接 (Outer Joins)或 NOT EXISTS. 例如 : SELECT FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT= A ); 為了提高效率 .改寫為 : (方法一 : 高效 ) SELECT . FROM EMP A,DEPT B WHERE A.DEPT_NO = B.DEPT(+) AND B.DEPT_NO IS NULL AND B.DEPT_CAT(+) = A (方法二 : 最高效 ) SELECT . FROM EMP E WHERE NOT EXISTS (SELECT X FROM DEPT D WHERE D.DEPT_NO = E.DEPT_NO AND DEPT_CAT = A ); 20.用表連接替換 EXISTS 通常來說 , 采用表連接的方式比 EXISTS 更有效率 SELECT ENAME FROM EMP E WHERE EXISTS (SELECT X FROM DEPT WHERE DEPT_NO = E.DEPT_NO AND DEPT_CAT = A ); (更高效 ) SELECT ENAME FROM DEPT D,EMP E WHERE E.DEPT_NO = D.DEPT_NO AND DEPT_CAT = A ; (譯者按 : 在 RBO 的情況下 ,前者的執(zhí) 行路徑包括 FILTER,后者使用 NESTED LOOP) 21.用 EXISTS 替換 DISTINCT 當提交一個包含一對多表信息 (比如部門表和雇員表 )的查詢時 ,避免在 SELECT子句中使用 DISTINCT. 一般可以考慮用 EXIST 替換 例如 : 低效 : SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D,EMP E WHERE D.DEPT_NO = E.DEPT_NO 高效 : SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT X FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO); EXISTS 使查詢更為迅速 ,因為 RDBMS 核心模塊將在子查詢的條件一旦滿足后 ,立刻返回結果 . 22.識別低效執(zhí)行的 SQL 語句 用下列 SQL 工具找出低效 SQL: SELECT EXECUTIONS , DISK_READS, BUFFER_GETS, ROUND(BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio, ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run, SQL_TEXT FROM V$SQLAREA WHERE EXECUTIONS0 AND BUFFER_GETS 0 AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS list 1 SELECT * 2 FROM dept, emp 3* WHERE emp.deptno = dept.deptno SQL set autotrace traceonly /*traceonly 可以不顯示執(zhí)行結果 */ SQL / 14 rows selected. Execution Plan - 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 NESTED LOOPS 2 1 TABLE ACCESS (FULL) OF EMP 3 1 TABLE ACCESS (BY INDEX ROWID) OF DEPT 4 3 INDEX (UNIQUE SCAN) OF PK_DEPT (UNIQUE) Statistics - 0 recursive calls 2 db block gets 30 consistent gets 0 physical reads 0 redo size 2598 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 14 rows processed 通過以上分析 ,可以得出實際的執(zhí)行步驟是 : 1. TABLE ACCESS (FULL) OF EMP 2. INDEX (UNIQUE SCAN) OF PK_DEPT (UNIQUE) 3. TABLE ACCESS (BY INDEX ROWID) OF DEPT 4. NESTED LOOPS (JOINING 1 AND 3) 注 : 目前許多第三方的工具如 TOAD 和 ORACLE 本身提供的工具如 OMS 的 SQL Analyze 都提供了極其方便的 EXPLAIN PLAN 工具 .也許喜歡圖形化界面的朋友們可以選用它們 . 25.用索引提高效率 索引是表的一個概念部分 ,用來提高檢索數(shù)據(jù)的效率 . 實際上 ,ORACLE 使用了一個復雜的自平衡 B-tree結構 . 通常 ,通過索引查詢數(shù)據(jù)比全表掃描要快 . 當 ORACLE找出執(zhí)行查詢和 Update語句的最佳路徑時 , ORACLE 優(yōu)化器將使用索引 . 同樣在聯(lián)結多個表時使用索引也可以提高效率 .另一個使用索引的好處是 ,它提供了主鍵 (primary key)的唯一性驗證 . 除了那些 LONG或 LONG RAW數(shù)據(jù)類型 , 你可以索引幾乎所有的列 . 通常 , 在大型表中使用索引特別有效 . 當然 ,你也會發(fā)現(xiàn) , 在掃描小表時 ,使用索引同樣能提高效率 . 雖然使用索引能得到查詢效率的提高 ,但是我們也必須注意到它的代價 . 索引需要空間來 存儲 ,也需要定期維護 , 每當有記錄在表中增減或索引列被修改時 , 索引本身也會被修改 . 這意味著每條記錄的 INSERT , DELETE , UPDATE將為此多付出 4 , 5 次的磁盤 I/O . 因為索引需要額外的存儲空間和處理 ,那些不必要的索引反而會使查詢反應時間變慢 . 譯者按 : 定期的重構索引是有必要的 . ALTER INDEX REBUILD 26.索引的操作 ORACLE 對索引有兩種訪問模式 . 索引唯一掃描 ( INDEX UNIQUE SCAN) 大多數(shù)情況下 , 優(yōu)化器通過 WHERE 子句訪問 INDEX. 例如 : 表 LODGING有兩個索引 : 建立在 LODGING列上的唯一性索引 LODGING_PK和建立在 MANAGER 列上的非唯一性索引 LODGING$MANAGER. SELECT * FROM LODGING WHERE LODGING = ROSE HILL ; 在內部 , 上述 SQL 將 被分成兩步執(zhí)行 , 首先 , LODGING_PK 索引將通過索引唯一掃描的方式被訪問 , 獲得相對應的 ROWID, 通過 ROWID 訪問表的方式執(zhí)行下一步檢索 . 如果被檢索返回的列包括在 INDEX列中 ,ORACLE將不執(zhí)行第二步的處理 (通過 ROWID訪問表 ).因為檢索數(shù)據(jù)保存在索引中 , 單單訪問索引就可以完全滿足查詢結果 . 下面 SQL 只需要 INDEX UNIQUE SCAN 操作 . SELECT LODGING FROM LODGING WHERE LODGING = ROSE HILL ; 索引范圍查詢 (INDEX RANGE SCAN) 適用于兩種情況 : 1. 基于一個范圍的檢索 2. 基于非唯一性索引的檢索 例 1: SELECT LODGING FROM LODGING WHERE LODGING LIKE M% ; WHERE子句條件包括一系列值 , ORACLE將通過索引范圍查詢的方式查詢 LODGING_PK . 由于索引范圍查詢將返回一組值 , 它的效率就要比索引唯一掃描 低一些 . 例 2: SELECT LODGING FROM LODGING WHERE MANAGER = BILL GATES ; 這個 SQL的執(zhí)行分兩步 , LODGING$MANAGER的索引范圍查詢 (得到所有符合條件記錄的 ROWID) 和下一步同過 ROWID訪問表得到 LODGING列的值 . 由于 LODGING$MANAGER是一個非唯一性的索引 ,數(shù)據(jù)庫不能對它執(zhí)行索引唯一掃描 . 由于 SQL 返回 LODGING 列 ,而它并不存在于 LODGING$MANAGER 索引中 , 所以在索引范圍查詢后會執(zhí)行一個通過 ROWID 訪問表的操作 . WHERE 子句中 , 如果索引列所對應的值的第一個字符由通配符 (WILDCARD)開始 , 索引將不被采用 . SELECT LODGING FROM LODGING WHERE MANAGER LIKE HANMAN ; 在這種情況下, ORACLE 將使用全表掃描 . 27.基礎表的選擇 基礎表 (Driving Table)是指被最先訪問的表 (通常以全表掃描的方式被訪問 ). 根據(jù)優(yōu)化器的不同 , SQL 語句中基礎表的選 擇是不一樣的 . 如果你使用的是 CBO (COST BASED OPTIMIZER),優(yōu)化器會檢查 SQL語句中的每個表的物理大小 ,索引的狀態(tài) ,然后選用花費最低的執(zhí)行路徑 . 如果你用 RBO (RULE BASED OPTIMIZER) , 并且所有的連接條件都有索引對應 , 在這種情況下 , 基礎表就是 FROM 子句中列在最后的那個表 . 舉例 : SELECT A.NAME , B.MANAGER FROM WORKER A, LODGING B WHERE A.LODGING = B.LODING; 由于 LODGING 表的 LODING 列上有一個索引 , 而且 WORKER 表中沒有相比較的索引 , WORKER表將被作為查詢中的基礎表 . 28.多個平等的索引 當 SQL 語句的執(zhí)行路徑可以使用分布在多個表上的多個索引時 , ORACLE 會同時使用多個索引并在運行時對它們的記錄進行合并 , 檢索出僅對全部索引有效的記錄 . 在 ORACLE 選擇執(zhí)行路徑時 ,唯一性索引的等級高于非唯一性索引 . 然而這個規(guī)則只有 當 WHERE 子句中索引列和常量比較才有效 .如果索引列和其他表的索引類相 比較 . 這種子句在優(yōu)化器中的等級是非常低的 . 如果不同表中兩個想同等級的索引將被引用 , FROM 子句中表的順序將決定哪個會被率先使用 . FROM 子句中最后的表的索引將有最高的優(yōu)先級 . 如果相同表中兩個想同等級的索引將被引用 , WHERE 子句中最先被引用的索引將有最高的優(yōu)先級 . 舉例 : DEPTNO 上有一個非唯一性索引 ,EMP_CAT 也有一個非唯一性索引 . SELECT ENAME, FROM EMP WHERE DEPT_NO = 20 AND EMP_CAT = A ; 這里 ,DEPTNO 索引將被最先檢索 ,然后同 EMP_CAT 索引檢索出的記錄進行合并 . 執(zhí)行路徑如下 : TABLE ACCESS BY ROWID ON EMP AND-EQUAL INDEX RANGE SCAN ON DEPT_IDX INDEX RANGE SCAN ON CAT_IDX 29. 等式比較和范圍比較 當 WHERE 子句中有索引列 , ORACLE 不能合并它們 ,ORACLE 將用范圍比較 . 舉例 : DEPTNO 上有一個非唯一性索引 ,EMP_CAT 也有一個非唯一性索引 . SELECT ENAME FROM EMP WHERE DEPTNO 20 AND EMP_CAT = A ; 這里只有 EMP_CAT索引被用到 ,然后所有的記錄將逐條與 DEPTNO條件進行比較 . 執(zhí)行路徑如下 : TABLE ACCESS BY ROWID ON EMP INDEX RANGE SCAN ON CAT_IDX 30.不明確的索引等級 當 ORACLE無法判斷索引的等級高低差別 ,優(yōu)化器將只使用一個索引 ,它就是在 WHERE子句中被列在最前面的 .舉例 : DEPTNO 上有一個非唯一性索引 ,EMP_CAT 也有一個非唯一性索引 . SELECT ENAME FROM EMP WHERE DEPTNO 20 AND EMP_CAT A ; 這里 , ORACLE 只用到了 DEPT_NO 索引 . 執(zhí)行路徑如下 : TABLE ACCESS BY ROWID ON EMP INDEX RANGE SCAN ON DEPT_IDX 譯者按 : 我們來試一下以下這種情況 : SQL select index_name, uniqueness from user_indexes where table_name = EMP; INDEX_NAME UNIQUENES - - EMPNO UNIQUE EMPTYPE NONUNIQUE SQL select * from emp where empno = 2 and emp_type = A ; no rows selected Execution Plan - 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF EMP 2 1 INDEX (RANGE SCAN) OF EMPTYPE (NON-UNIQUE) 雖然 EMPNO是唯一性索引 ,但是由于它所做的是范圍比較 , 等級要比非唯一性索引的等式比較低 ! 31.強制索引失效 如果兩個或以上索引具有相同的等級 ,你可以強制命令 ORACLE 優(yōu)化器使用其中的一個 (通過它 ,檢索出的記錄數(shù)量少 ) . 舉例 : SELECT ENAME FROM EMP WHERE EMPNO = 7935 AND DEPTNO + 0 = 10 /*DEPTNO 上的索引將失效 */ AND EMP_TYPE | = A /*EMP_TYPE 上的索引將失效 */ 這是一種相當直接的提高查詢效率的辦法 . 但是你必須謹慎考慮這種策略 ,一般來說 ,只有在你希望單獨優(yōu)化幾個 SQL 時才能采用它 . 這里有一個例子關于何時采用這種策略 , 假設在 EMP 表的 EMP_TYPE 列上有一個非唯一性的索引而 EMP_CLASS 上沒有索引 . SELECT ENAME FROM EMP WHERE EMP_TYPE = A AND EMP_CLASS = X ; 優(yōu)化器會注意到 EMP_TYPE 上的索引并使用它 . 這是目前唯一的選擇 . 如果 ,一段時間以后 ,另一個非唯一性建立在 EMP_CLASS 上 ,優(yōu)化器必須對兩個索引進行選擇 ,在通常情況下 ,優(yōu)化器將使用兩個索引并在他們的結果集合上執(zhí)行排序及合并 . 然而 ,如果其中一個索引( EMP_TYPE)接近于唯一性而另一個索引( EMP_CLASS)上有幾千個重復的值 . 排序及合并就會成為一種不必要的負擔 . 在這種情況下 ,你希望使優(yōu)化 器屏蔽掉 EMP_CLASS 索引 . 用下面的方案就可以解決問題 . SELECT ENAME FROM EMP WHERE EMP_TYPE = A AND EMP_CLASS| = X ; 32.避免在索引列上使用計算 WHERE 子句中,如果索引列是函數(shù)的一部分優(yōu)化器將不使用索引而使用全表掃描 舉例 : 低效: SELECT FROM DEPT WHERE SAL * 12 25000; 高效 : SELECT FROM DEPT WHERE SAL 25000/12; 譯者按 :這是一個非常實用的規(guī)則,請務必牢記 33.自動選擇索引 如果表中有兩個以上(包括兩個)索引,其中有一個唯一性索引,而其他是非唯一性 在這種情況下, ORACLE 將使用唯一性索引而完全忽略非唯一性索引 舉例 : SELECT ENAME FROM EMP WHERE EMPNO = 2326 AND DEPTNO = 20 ; 這里,只有 EMPNO 上的索引是唯一性的,所以 EMPNO 索引將用來檢索記錄 TABLE ACCESS BY ROWID ON EMP INDEX UNIQUE SCAN ON EMP_NO_IDX 34. 避免在索引列上使用 NOT 通常, 我們要避免在索引列上使用 NOT, NOT 會產生在和在索引列上使用函數(shù)相同的 影響 . 當 ORACLE”遇到” NOT,他就會停止使用索引轉而執(zhí)行全表掃描 . 舉例 : 低效 : (這里 ,不使用索引 ) SELECT FROM DEPT WHERE DEPT_CODE NOT = 0; 高效 : (這里 ,使用了索引 ) SELECT FROM DEPT WHERE DEPT_CODE 0; 需要注意的是 ,在某些時候 , ORACLE 優(yōu)化器會自動將 NOT 轉化成相對應的關系操作符 . NOT to = to = NOT 譯者按 : 在這個例子中 ,作者犯了一些錯誤 . 例子中的低效率 SQL 是不能被執(zhí)行的 . 我做了一些測試 : SQL select * from emp where NOT empno 1; no rows selected Execution Plan - 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF EMP 2 1 INDEX (RANGE SCAN) OF EMPNO (UNIQUE) SQL select * from emp where empno =替代 如果 DEPTNO 上有一個索引 , 高效 : SELECT * FROM EMP WHERE DEPTNO =4 低效 : SELECT * FROM EMP WHERE DEPTNO 3 兩者的區(qū)別在于 , 前者
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024版換熱站安裝合同模板
- 2025借款合同的時效及相關難點
- 2024版房產委托代持合同
- 2025年廣告制作合同書格式
- 二零二五年度住宅小區(qū)道路維修及養(yǎng)護合同3篇
- 2025年度消防器材安全宣傳合同范本3篇
- 2024洗煤廠煤炭洗選技術研究租賃合同范本3篇
- 2025設備采購合同(詳細)
- 2025版大數(shù)據(jù)分析股權三方轉讓及商業(yè)應用合同2篇
- 2024版建筑工程拆除及清理合同3篇
- 工行個人小額貸款合同樣本
- 江西省萍鄉(xiāng)市2023-2024學年高一上學期期末考試數(shù)學試題(解析版)
- Unit 5 Here and now Section B project 說課稿 2024-2025學年人教版(2024)七年級英語下冊標簽標題
- 2024-2025學年上學期深圳初中地理七年級期末模擬卷1
- 2024年地理知識競賽試題200題及答案
- 肝衰竭診治指南(2024年版)解讀
- 化學反應工程智慧樹知到期末考試答案章節(jié)答案2024年浙江工業(yè)大學
- 人生悟理-透過物理看人生智慧樹知到期末考試答案2024年
- 兒童劇劇本三只小豬
- 《職業(yè)健康培訓》
- 建筑施工企業(yè)安全生產管理制度
評論
0/150
提交評論