轉Oracle語句優化53個規則詳解 (二)

wuhesheng發表於2008-08-20
31.       強制索引失效

    如果兩個或以上索引具有相同的等級,你可以強制命令ORACLE優化器使用其中的一個(通過它,檢索出的記錄數量少) .

    舉例:

    SELECT ENAME
 FROM EMP
 WHERE EMPNO = 7935
 AND DEPTNO + 0 = 10    /*DEPTNO上的索引將失效*/
 AND EMP_TYPE || ‘’ = ‘A’ /*EMP_TYPE上的索引將失效*/

    這是一種相當直接的提高查詢效率的辦法。 但是你必須謹慎考慮這種策略,一般來說,只有在你希望單獨優化幾個SQL時才能採用它。

    這裡有一個例子關於何時採用這種策略,

    假設在EMP表的EMP_TYPE列上有一個非唯一性的索引而EMP_CLASS上沒有索引。

    SELECT ENAME
 FROM EMP
 WHERE EMP_TYPE = ‘A’
 AND EMP_CLASS = ‘X’;

    優化器會注意到EMP_TYPE上的索引並使用它。 這是目前唯一的選擇。 如果,一段時間以後,另一個非唯一性建立在EMP_CLASS上,優化器必須對兩個索引進行選擇,在通常情況下,優化器將使用兩個索引並在他們的結果集合上執行排序及合併。然而,如果其中一個索引(EMP_TYPE)接近於唯一性而另一個索引(EMP_CLASS)上有幾千個重複的值。排序及合併就會成為一種不必要的負擔。 在這種情況下,你希望使優化器遮蔽掉EMP_CLASS索引。

    用下面的方案就可以解決問題。

    SELECT ENAME
 FROM EMP
 WHERE EMP_TYPE = ‘A’
 AND EMP_CLASS||‘’ = ‘X’;

    32.       避免在索引列上使用計算。

    WHERE子句中,如果索引列是函式的一部分。優化器將不使用索引而使用全表掃描。

    舉例:

    低效:

 SELECT …
    FROM DEPT
WHERE SAL * 12 > 25000;

    高效:

 SELECT …
    FROM DEPT
 WHERE SAL > 25000/12;

    譯者按:這是一個非常實用的規則,請務必牢記

    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會產生在和在索引列上使用函式相同的影響。 當ORACLE“遇到”NOT,他就會停止使用索引轉而執行全表掃描。

    舉例:

    低效: (這裡,不使用索引)

    SELECT …
    FROM DEPT
 WHERE DEPT_CODE NOT = 0;

    高效: (這裡,使用了索引)

    SELECT …
    FROM DEPT
 WHERE DEPT_CODE > 0;

    需要注意的是,在某些時候, ORACLE優化器會自動將NOT轉化成相對應的關係操作符。

    NOT > to <=
 NOT >= to <
 NOT < to >=
 NOT <= to >

    譯者按:在這個例子中,作者犯了一些錯誤。 例子中的低效率SQL是不能被執行的。

    我做了一些測試:

    SQL> select * from emp where NOT empno > 1;
 no rows selected
 Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
 2    1     INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE)

    SQL> select * from emp where empno <= 1;
 no rows selected
 Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
 2    1     INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE)

    兩者的效率完全一樣,也許這符合作者關於“ 在某些時候, ORACLE優化器會自動將NOT轉化成相對應的關係操作符” 的觀點。

    35.       用>=替代>

    如果DEPTNO上有一個索引,

    高效:

    SELECT *
 FROM EMP
 WHERE DEPTNO >=4

    低效:

    SELECT *
 FROM EMP
 WHERE DEPTNO >3

    兩者的區別在於, 前者DBMS將直接跳到第一個DEPT等於4的記錄而後者將首先定位到DEPTNO=3的記錄並且向前掃描到第一個DEPT大於3的記錄。

    36.       用UNION替換OR (適用於索引列)

    通常情況下, 用UNION替換WHERE子句中的OR將會起到較好的效果。 對索引列使用OR將造成全表掃描。注意, 以上規則只針對多個索引列有效。 如果有column沒有被索引, 查詢效率可能會因為你沒有選擇OR而降低。

    在下面的例子中, LOC_ID 和REGION上都建有索引。

    高效:

 SELECT LOC_ID , LOC_DESC , REGION
 FROM LOCATION
 WHERE LOC_ID = 10
 UNION
 SELECT LOC_ID , LOC_DESC , REGION
 FROM LOCATION
 WHERE REGION = “MELBOURNE”

    低效:

 SELECT LOC_ID , LOC_DESC , REGION
 FROM LOCATION
 WHERE LOC_ID = 10 OR REGION = “MELBOURNE”

    如果你堅持要用OR, 那就需要返回記錄最少的索引列寫在最前面。

    注意:

    WHERE KEY1 = 10   (返回最少記錄)

    OR KEY2 = 20        (返回最多記錄)

    ORACLE 內部將以上轉換為

 WHERE KEY1 = 10 AND((NOT KEY1 = 10) AND KEY2 = 20)

    譯者按:

    下面的測試資料僅供參考: (a = 1003 返回一條記錄 , b = 1 返回1003條記錄)

    SQL> select * from unionvsor /*1st test*/
 2   where a = 1003 or b = 1;
 1003 rows selected.
 Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   CONCATENATION
 2    1     TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'
 3    2       INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE)
    4    1     TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'
 5    4       INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE)

    Statistics

 ----------------------------------------------------------

    0 recursive calls
 0 db block gets
 144 consistent gets
 0 physical reads
 0 redo size
 63749 bytes sent via SQL*Net to client
 7751 bytes received via SQL*Net from client
 68 SQL*Net roundtrips to/from client
 0 sorts (memory)
    0 sorts (disk)
    1003 rows processed

 SQL> select * from unionvsor /*2nd test*/
 2 where b = 1 or a = 1003 ;
 1003 rows selected.
 Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   CONCATENATION
 2    1     TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'
 3    2       INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE)
    4    1     TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'
 5    4       INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE)

    Statistics

 ----------------------------------------------------------

    0 recursive calls
 0 db block gets
 143 consistent gets
 0 physical reads
 0 redo size
 63749 bytes sent via SQL*Net to client
 7751 bytes received via SQL*Net from client
 68 SQL*Net roundtrips to/from client 0 sorts (memory)
    0 sorts (disk)
    1003 rows processed

    SQL> select * from unionvsor /*3rd test*/
 2 where a = 1003
 3 union
 4   select * from unionvsor
 5   where b = 1;
 1003 rows selected. Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   SORT (UNIQUE)
    2    1     UNION-ALL
 3    2       TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'
 4    3         INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE)
    5    2       TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'
 6    5         INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE)

    Statistics

 ----------------------------------------------------------

    0 recursive calls
 0 db block gets
 10 consistent gets
 0 physical reads
 0 redo size
 63735 bytes sent via SQL*Net to client
 7751 bytes received via SQL*Net from client
 68 SQL*Net roundtrips to/from client 1 sorts (memory)
    0 sorts (disk)
    1003 rows processed

 用UNION的效果可以從consistent gets和 SQL*NET的資料交換量的減少看出

    37.       用IN來替換OR

    下面的查詢可以被更有效率的語句替換:

    低效:

    SELECT…
    FROM LOCATION
 WHERE LOC_ID = 10
 OR     LOC_ID = 20
 OR     LOC_ID = 30

    高效:

 SELECT…
    FROM LOCATION
 WHERE LOC_IN IN (10,20,30);

    譯者按:這是一條簡單易記的規則,但是實際的執行效果還須檢驗,在ORACLE8i下,兩者的執行路徑似乎是相同的。

    38.       避免在索引列上使用IS NULL和IS NOT NULL

 避免在索引中使用任何可以為空的列,ORACLE將無法使用該索引。對於單列索引,如果列包含空值,索引中將不存在此記錄。 對於複合索引,如果每個列都為空,索引中同樣不存在此記錄。 如果至少有一個列不為空,則記錄存在於索引中。

    舉例:

 如果唯一性索引建立在表的A列和B列上, 並且表中存在一條記錄的A,B值為(123,null) , ORACLE將不接受下一條具有相同A,B值(123,null)的記錄(插入)。然而如果所有的索引列都為空,ORACLE將認為整個鍵值為空而空不等於空。 因此你可以插入1000條具有相同鍵值的記錄,當然它們都是空!

    因為空值不存在於索引列中,所以WHERE子句中對索引列進行空值比較將使ORACLE停用該索引。

    舉例:

    低效: (索引失效)

    SELECT …
    FROM DEPARTMENT
 WHERE DEPT_CODE IS NOT NULL;

    高效: (索引有效)

    SELECT …
    FROM DEPARTMENT
 WHERE DEPT_CODE >=0;

 39.       總是使用索引的第一個列

 如果索引是建立在多個列上, 只有在它的第一個列(leading column)被where子句引用時,優化器才會選擇使用該索引。

    譯者按:這也是一條簡單而重要的規則。 見以下例項。

    SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10));
 Table created.
 SQL> create index multindex on multiindexusage(inda,indb);
 Index created.
 SQL> set autotrace traceonly
    SQL> select * from multiindexusage where inda = 1;
 Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MULTIINDEXUSAGE'
 2    1     INDEX (RANGE SCAN) OF 'MULTINDEX' (NON-UNIQUE)

    SQL> select * from multiindexusage where indb = 1;
 Execution Plan

 ----------------------------------------------------------

    0      SELECT STATEMENT ptimizer=CHOOSE
 1    0   TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE'

    很明顯, 當僅引用索引的第二個列時,優化器使用了全表掃描而忽略了索引

    40.       ORACLE內部操作

 當執行查詢時,ORACLE採用了內部的操作。 下表顯示了幾種重要的內部操作。

ORACLE Clause 內部操作
ORDER BY SORT ORDER BY
UNION UNION-ALL
MINUS MINUS
INTERSECT INTERSECT
DISTINCT,MINUS,INTERSECT,UNION SORT UNIQUE
MIN,MAX,COUNT SORT AGGREGATE
GROUP BY SORT GROUP BY
ROWNUM COUNT or COUNT STOPKEY
Queries involving Joins SORT JOIN,MERGE JOIN,NESTED LOOPS
CONNECT BY CONNECT BY

41. 用UNION-ALL 替換UNION ( 如果有可能的話)

當SQL語句需要UNION兩個查詢結果集合時,這兩個結果集合會以UNION-ALL的方式被合併, 然後在輸出最終結果前進行排序。

如果用UNION ALL替代UNION, 這樣排序就不是必要了。 效率就會因此得到提高。

舉例:

 低效:

 SELECT ACCT_NUM, BALANCE_AMT
 FROM DEBIT_TRANSACTIONS
 WHERE TRAN_DATE = ‘31-DEC-95’
 UNION
 SELECT ACCT_NUM, BALANCE_AMT
 FROM DEBIT_TRANSACTIONS
 WHERE TRAN_DATE = ‘31-DEC-95’

 高效:

 SELECT ACCT_NUM, BALANCE_AMT
 FROM DEBIT_TRANSACTIONS
 WHERE TRAN_DATE = ‘31-DEC-95’
 UNION ALL
 SELECT ACCT_NUM, BALANCE_AMT
 FROM DEBIT_TRANSACTIONS
 WHERE TRAN_DATE = ‘31-DEC-95’

譯者按:需要注意的是,UNION ALL 將重複輸出兩個結果集合中相同記錄。 因此各位還是要從業務需求分析使用UNION ALL的可行性。

UNION 將對結果集合排序,這個操作會使用到SORT_AREA_SIZE這塊記憶體。 對於這塊記憶體的優化也是相當重要的。 下面的SQL可以用來查詢排序的消耗量

Select substr(name,1,25) "Sort Area Name",
 substr(value,1,15) "Value"
 from v$sysstat
 where name like 'sort%'

>>

42. 使用提示(Hints)

對於表的訪問,可以使用兩種Hints.

 FULL 和 ROWID

FULL hint 告訴ORACLE使用全表掃描的方式訪問指定表。

例如:

 SELECT /* FULL(EMP) */ *
 FROM EMP
 WHERE EMPNO = 7893;

ROWID hint 告訴ORACLE使用TABLE ACCESS BY ROWID的操作訪問表。

通常, 你需要採用TABLE ACCESS BY ROWID的方式特別是當訪問大表的時候, 使用這種方式, 你需要知道ROIWD的值或者使用索引。

如果一個大表沒有被設定為快取(CACHED)表而你希望它的資料在查詢結束是仍然停留在SGA中,你就可以使用CACHE hint 來告訴優化器把資料保留在SGA中。 通常CACHE hint 和 FULL hint 一起使用。

例如:

 SELECT /* FULL(WORKER) CACHE(WORKER)*/ *
 FROM WORK;

索引hint 告訴ORACLE使用基於索引的掃描方式。 你不必說明具體的索引名稱

 例如:

 SELECT /* INDEX(LODGING) */ LODGING
 FROM LODGING
 WHERE MANAGER = ‘BILL GATES’;

在不使用hint的情況下, 以上的查詢應該也會使用索引,然而,如果該索引的重複值過多而你的優化器是CBO, 優化器就可能忽略索引。 在這種情況下, 你可以用INDEX hint強制ORACLE使用該索引。

ORACLE hints 還包括ALL_ROWS, FIRST_ROWS, RULE,USE_NL, USE_MERGE, USE_HASH 等等。

譯者按:使用hint , 表示我們對ORACLE優化器預設的執行路徑不滿意,需要手工修改。這是一個很有技巧性的工作。 我建議只針對特定的,少數的SQL進行hint的優化。對ORACLE的優化器還是要有信心(特別是CBO)

43. 用WHERE替代ORDER BY

 ORDER BY 子句只在兩種嚴格的條件下使用索引。

ORDER BY中所有的列必須包含在相同的索引中並保持在索引中的排列順序。

ORDER BY中所有的列必須定義為非空。

WHERE子句使用的索引和ORDER BY子句中所使用的索引不能並列。

例如:

 表DEPT包含以下列:

DEPT_CODE PK NOT NULL
 DEPT_DESC NOT NULL
 DEPT_TYPE NULL

非唯一性的索引(DEPT_TYPE)

低效: (索引不被使用)

SELECT DEPT_CODE
 FROM DEPT
 ORDER BY DEPT_TYPE

EXPLAIN PLAN:
  SORT ORDER BY
    TABLE ACCESS FULL

 高效: (使用索引)

SELECT DEPT_CODE
 FROM DEPT
 WHERE DEPT_TYPE > 0

 EXPLAIN PLAN:
  TABLE ACCESS BY ROWID ON EMP
   INDEX RANGE SCAN ON DEPT_IDX

 譯者按:ORDER BY 也能使用索引! 這的確是個容易被忽視的知識點。 我們來驗證一下:

SQL> select * from emp order by empno;
Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT ptimizer=CHOOSE
 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
 2 1 INDEX (FULL SCAN) OF 'EMPNO' (UNIQUE)

44. 避免改變索引列的型別。

當比較不同資料型別的資料時, ORACLE自動對列進行簡單的型別轉換。

假設 EMPNO是一個數值型別的索引列。

SELECT …
FROM EMP
 WHERE EMPNO = ‘123’

 實際上,經過ORACLE型別轉換, 語句轉化為:

 SELECT …
FROM EMP
 WHERE EMPNO = TO_NUMBER(‘123’)

幸運的是,型別轉換沒有發生在索引列上,索引的用途沒有被改變。

現在,假設EMP_TYPE是一個字元型別的索引列。

SELECT …
FROM EMP
WHERE EMP_TYPE = 123

 這個語句被ORACLE轉換為:

 SELECT …
FROM EMP
 WHERE TO_NUMBER(EMP_TYPE)=123

 因為內部發生的型別轉換, 這個索引將不會被用到!

譯者按:為了避免ORACLE對你的SQL進行隱式的型別轉換, 最好把型別轉換用顯式表現出來。 注意當字元和數值比較時, ORACLE會優先轉換數值型別到字元型別。

45.       需要當心的WHERE子句

 某些SELECT 語句中的WHERE子句不使用索引。 這裡有一些例子。

    在下面的例子裡, ‘!=’ 將不使用索引。 記住, 索引只能告訴你什麼存在於表中, 而不能告訴你什麼不存在於表中。

    不使用索引:

 SELECT ACCOUNT_NAME
 FROM TRANSACTION
 WHERE AMOUNT !=0;

 使用索引:

 SELECT ACCOUNT_NAME
 FROM TRANSACTION
 WHERE AMOUNT >0;

 下面的例子中, ‘||’是字元連線函式。 就象其他函式那樣, 停用了索引。

    不使用索引:

 SELECT ACCOUNT_NAME,AMOUNT
 FROM TRANSACTION
 WHERE ACCOUNT_NAME||ACCOUNT_TYPE=‘AMEXA’;

 使用索引:

 SELECT ACCOUNT_NAME,AMOUNT
 FROM TRANSACTION
 WHERE ACCOUNT_NAME = ‘AMEX’AND ACCOUNT_TYPE=‘ A’;

 下面的例子中, ‘+’是數學函式。 就象其他數學函式那樣, 停用了索引。

    不使用索引:

 SELECT ACCOUNT_NAME, AMOUNT
 FROM TRANSACTION
 WHERE AMOUNT + 3000 >5000;

 使用索引:

 SELECT ACCOUNT_NAME, AMOUNT
 FROM TRANSACTION
 WHERE AMOUNT > 2000 ;

 下面的例子中,相同的索引列不能互相比較,這將會啟用全表掃描。

    不使用索引:

 SELECT ACCOUNT_NAME, AMOUNT
 FROM TRANSACTION
 WHERE ACCOUNT_NAME = NVL(:ACC_NAME,ACCOUNT_NAME);

 使用索引:

 SELECT ACCOUNT_NAME, AMOUNT
 FROM TRANSACTION
 WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME,‘%’);

 譯者按:如果一定要對使用函式的列啟用索引, ORACLE新的功能: 基於函式的索引(Function-Based Index) 也許是一個較好的方案。

    CREATE INDEX EMP_I ON EMP (UPPER(ename)); /*建立基於函式的索引*/
 SELECT * FROM emp WHERE UPPER(ename) = ‘BLACKSNAIL’; /*將使用索引*/

 46.       連線多個掃描

 如果你對一個列和一組有限的值進行比較, 優化器可能執行多次掃描並對結果進行合併連線。

    舉例:

 SELECT *
 FROM LODGING
 WHERE MANAGER IN (‘BILL GATES’,‘KEN MULLER’);

 優化器可能將它轉換成以下形式

 SELECT *
 FROM LODGING
 WHERE MANAGER = ‘BILL GATES’OR MANAGER = ‘KEN MULLER’;

 當選擇執行路徑時, 優化器可能對每個條件採用LODGING$MANAGER上的索引範圍掃描。 返回的ROWID用來訪問LODGING表的記錄 (通過TABLE ACCESS BY ROWID 的方式)。 最後兩組記錄以連線(CONCATENATION)的形式被組合成一個單一的集合。

    Explain Plan :
 SELECT STATEMENT ptimizer=CHOOSE
 CONCATENATION
  TABLE ACCESS (BY INDEX ROWID) OF LODGING
   INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE)
     TABLE ACCESS (BY INDEX ROWID) OF LODGING
   INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE)

    譯者按:本節和第37節似乎有矛盾之處。

    47.       CBO下使用更具選擇性的索引

 基於成本的優化器(CBO, Cost-Based Optimizer)對索引的選擇性進行判斷來決定索引的使用是否能提高效率。

    如果索引有很高的選擇性, 那就是說對於每個不重複的索引鍵值,只對應數量很少的記錄。

    比如, 表中共有100條記錄而其中有80個不重複的索引鍵值。 這個索引的選擇性就是80/100 = 0.8 . 選擇性越高, 通過索引鍵值檢索出的記錄就越少。

    如果索引的選擇性很低, 檢索資料就需要大量的索引範圍查詢操作和ROWID 訪問表的操作。 也許會比全表掃描的效率更低。

    譯者按:

 下列經驗請參閱:

 a.       如果檢索資料量超過30%的表中記錄數。使用索引將沒有顯著的效率提高。
    b.       在特定情況下, 使用索引也許會比全表掃描慢, 但這是同一個數量級上的區別。 而通常情況下,使用索引比全表掃描要快幾倍乃至幾千倍!

    48.       避免使用耗費資源的操作

 帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啟動SQL引擎執行耗費資源的排序(SORT)功能。 DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序。

    例如,一個UNION查詢,其中每個查詢都帶有GROUP BY子句, GROUP BY會觸發嵌入排序(NESTED SORT) ; 這樣, 每個查詢需要執行一次排序, 然後在執行UNION時, 又一個唯一排序(SORT UNIQUE)操作被執行而且它只能在前面的嵌入排序結束後才能開始執行。 嵌入的排序的深度會大大影響查詢的效率。

    通常, 帶有UNION, MINUS , INTERSECT的SQL語句都可以用其他方式重寫。

    譯者按:如果你的資料庫的SORT_AREA_SIZE調配得好, 使用UNION , MINUS, INTERSECT也是可以考慮的, 畢竟它們的可讀性很強

49.       優化GROUP BY

 提高GROUP BY 語句的效率, 可以通過將不需要的記錄在GROUP BY 之前過濾掉。下面兩個查詢返回相同結果但第二個明顯就快了許多。

    低效:

 SELECT JOB , AVG(SAL)
    FROM EMP
 GROUP by JOB
 HAVING JOB = ‘PRESIDENT’
 OR JOB = ‘MANAGER’

 高效:

 SELECT JOB , AVG(SAL)
    FROM EMP
 WHERE JOB = ‘PRESIDENT’
 OR JOB = ‘MANAGER’GROUP by JOB

 譯者按:本節和14節相同。 可略過。

    50.       使用日期當

 使用日期是,需要注意如果有超過5位小數加到日期上, 這個日期會進到下一天!

    例如:

 1.

 SELECT TO_DATE(‘01-JAN-93’+.99999)
    FROM DUAL;
 Returns:“01-JAN-93 23:59:59‘

 2.

 SELECT TO_DATE(’01-JAN-93‘+.999999)
    FROM DUAL;
    Returns:“02-JAN-93 00:00:00‘

 譯者按:雖然本節和SQL效能優化沒有關係, 但是作者的功力可見一斑

 51.   使用顯式的遊標(CURSORs)

    使用隱式的遊標,將會執行兩次操作。 第一次檢索記錄, 第二次檢查TOO MANY ROWS 這個exception . 而顯式遊標不執行第二次操作。

    52.   優化EXPORT和IMPORT

 使用較大的BUFFER(比如10MB , 10,240,000)可以提高EXPORT和IMPORT的速度。

    ORACLE將盡可能地獲取你所指定的記憶體大小,即使在記憶體不滿足,也不會報錯。這個值至少要和表中最大的列相當,否則列值會被截斷。

    譯者按:可以肯定的是, 增加BUFFER會大大提高EXPORT , IMPORT的效率。 (曾經碰到過一個CASE, 增加BUFFER後,IMPORT/EXPORT快了10倍!)

    作者可能犯了一個錯誤: “這個值至少要和表中最大的列相當,否則列值會被截斷。 ”其中最大的列也許是指最大的記錄大小。

    關於EXPORT/IMPORT的優化,CSDN論壇中有一些總結性的貼子,比如關於BUFFER引數, COMMIT引數等等, 詳情請查。

    53.   分離表和索引

 總是將你的表和索引建立在不同的表空間內(TABLESPACES)。 決不要將不屬於ORACLE內部系統的物件存放到SYSTEM表空間裡。 同時,確保資料表空間和索引表空間置於不同的硬碟上。

    譯者按:“同時,確保資料表空間和索引表空間置與不同的硬碟上。”可能改為如下更為準確 “同時,確保資料表空間和索引表空間置與不同的硬碟控制卡控制的硬碟上。”

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/119501/viewspace-430110/,如需轉載,請註明出處,否則將追究法律責任。

相關文章