Oracle的優化器共有
a
b
c
設置缺省的優化器
為了使用基於成本的優化器(CBO
如果數據庫的優化器模式設置為選擇性(CHOOSE)
在缺省情況下
a
全表掃描就是順序地訪問表中每條記錄
b
你可以采用基於ROWID的訪問方式情況
為了不重復解析相同的SQL語句
可惜的是ORACLE只對簡單的表提供高速緩沖(cache buffering)
數據庫管理員必須在init
當你向ORACLE 提交一個SQL語句
這裡需要注明的是
共享的語句必須滿足三個條件
A
當前被執行的語句和共享池中的語句必須完全相同
例如
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語句能否在這兩個用戶之間共享
[NextPage]
SQL 能否共享 原因
select max(sal_cap) from sal_limit; 不能 每個用戶都有一個private synonym
select count(*
select a
C
例如
a
select pin
select pin
b
select pin
select pin
ORACLE的解析器按照從右到左的順序處理FROM子句中的表名
例如
表 TAB
表 TAB
選擇TAB
select count(*) from tab
選擇TAB
select count(*) from tab
如果有
例如
SELECT *
FROM LOCATION L
CATEGORY C
EMP E
WHERE E
AND E
AND E
將比下列SQL更有效率
SELECT *
FROM EMP E
LOCATION L
CATEGORY C
WHERE E
AND E
AND E
[NextPage]
ORACLE采用自下而上的順序解析WHERE子句
例如
(低效
SELECT …
FROM EMP E
WHERE SAL >
AND JOB =
AND
WHERE MGR=E
(高效
SELECT …
FROM EMP E
WHERE
WHERE MGR=E
AND SAL >
AND JOB =
當你想在SELECT子句中列出所有的COLUMN時
當執行每條SQL語句時
例如
方法
SELECT EMP_NAME
FROM EMP
WHERE EMP_NO =
SELECT EMP_NAME
FROM EMP
WHERE EMP_NO =
方法
DECLARE
CURSOR C
SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C
FETCH C
OPEN C
FETCH C
CLOSE C
方法
SELECT A
B
FROM EMP A
WHERE A
AND B
注意
在SQL*Plus
[NextPage]
使用DECODE函數可以避免重復掃描相同記錄或重復連接相同的表
例如
SELECT COUNT(*)
FROM EMP
WHERE DEPT_NO =
AND ENAME LIKE
SELECT COUNT(*)
FROM EMP
WHERE DEPT_NO =
AND ENAME LIKE
你可以用DECODE函數高效地得到相同結果
SELECT COUNT(DECODE(DEPT_NO
COUNT(DECODE(DEPT_NO
SUM(DECODE(DEPT_NO
SUM(DECODE(DEPT_NO
FROM EMP WHERE ENAME LIKE
類似的
如果你有幾個簡單的數據庫查詢語句
例如
SELECT NAME
FROM EMP
WHERE EMP_NO =
SELECT NAME
FROM DPT
WHERE DPT_NO =
SELECT NAME
FROM CAT
WHERE CAT_TYPE =
上面的
SELECT E
FROM CAT C
WHERE NVL(
AND NVL(
AND NVL(
AND E
AND D
AND C
(譯者按
[NextPage]
最高效的刪除重復記錄方法 ( 因為使用了ROWID)
DELETE FROM EMP E
WHERE E
FROM EMP X
WHERE X
當刪除表中的記錄時
而當運用TRUNCATE時
(譯者按
只要有可能
a
b
c
d
(譯者按
和一般的觀點相反
(譯者按
避免使用HAVING子句
例如
低效
SELECT REGION
FROM LOCATION
GROUP BY REGION
HAVING REGION REGION !=
AND REGION !=
高效
SELECT REGION
FROM LOCATION
WHERE REGION REGION !=
AND REGION !=
GROUP BY REGION
(譯者按
[NextPage]
在含有子查詢的SQL語句中
例如
低效
SELECT TAB_NAME
FROM TABLES
WHERE TAB_NAME = ( SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION =
AND DB_VER= ( SELECT DB_VER
FROM TAB_COLUMNS
WHERE VERSION =
高效
SELECT TAB_NAME
FROM TABLES
WHERE (TAB_NAME
= ( SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION =
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 =
高效
UPDATE EMP
SET (EMP_CAT
= (SELECT MAX(CATEGORY)
FROM EMP_CATEGORIES)
WHERE EMP_DEPT =
SELECT H
FROM HISTORY_TYPE T
WHERE H
AND H
GROUP BY H
通過調用下面的函數可以提高效率
FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN VARCHAR
AS
TDESC VARCHAR
CURSOR C
SELECT TYPE_DESC
FROM HISTORY_TYPE
WHERE HIST_TYPE = TYP;
BEGIN
OPEN C
FETCH C
CLOSE C
RETURN (NVL(TDESC
END;
FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN VARCHAR
AS
ENAME VARCHAR
CURSOR C
SELECT ENAME
FROM EMP
WHERE EMPNO=EMP;
BEGIN
OPEN C
FETCH C
CLOSE C
RETURN (NVL(ENAME
END;
SELECT H
H
FROM EMP_HISTORY H
GROUP BY H
(譯者按
[NextPage]
當在SQL語句中連接多個表時
(譯者注
在許多基於基礎表的查詢中
低效
SELECT *
FROM EMP (基礎表)
WHERE EMPNO >
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC =
高效
SELECT *
FROM EMP (基礎表)
WHERE EMPNO >
AND EXISTS (SELECT
FROM DEPT
WHERE DEPT
AND LOC =
(譯者按
在子查詢中
例如
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO
FROM DEPT
WHERE DEPT_CAT=
為了提高效率
(方法一
SELECT …
FROM EMP A
WHERE A
AND B
AND B
(方法二
SELECT …
FROM EMP E
WHERE NOT EXISTS (SELECT
FROM DEPT D
WHERE D
AND DEPT_CAT =
通常來說
SELECT ENAME
FROM EMP E
WHERE EXISTS (SELECT
FROM DEPT
WHERE DEPT_NO = E
AND DEPT_CAT =
(更高效)
SELECT ENAME
FROM DEPT D
WHERE E
AND DEPT_CAT =
(譯者按
[NextPage]
當提交一個包含一對多表信息(比如部門表和雇員表)的查詢時
例如
低效
SELECT DISTINCT DEPT_NO
FROM DEPT D
WHERE D
高效
SELECT DEPT_NO
FROM DEPT D
WHERE EXISTS ( SELECT
FROM EMP E
WHERE E
EXISTS 使查詢更為迅速
用下列SQL工具找出低效SQL
SELECT EXECUTIONS
ROUND((BUFFER_GETS
ROUND(DISK_READS/EXECUTIONS
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>
AND BUFFER_GETS >
AND (BUFFER_GETS
ORDER BY
(譯者按
SQL trace 工具收集正在執行的SQL的性能狀態數據並記錄到一個跟蹤文件中
設置SQL TRACE在會話級別
有效
ALTER SESSION SET SQL_TRACE TRUE
設置SQL TRACE 在整個數據庫有效仿
(譯者按
EXPLAIN PLAN 是一個很好的分析SQL語句的工具
你需要按照從裡到外
NESTED LOOP是少數不按照上述規則處理的操作
譯者按
舉例
SQL> list
SQL> set autotrace traceonly /*traceonly 可以不顯示執行結果*/
SQL> /
Execution Plan
Statistics
通過以上分析
注
[NextPage]
索引是表的一個概念部分
除了那些LONG或LONG RAW數據類型
雖然使用索引能得到查詢效率的提高
譯者按
ALTER INDEX
ORACLE對索引有兩種訪問模式
索引唯一掃描 ( INDEX UNIQUE SCAN)
大多數情況下
例如
表LODGING有兩個索引
SELECT *
FROM LODGING
WHERE LODGING =
在內部
如果被檢索返回的列包括在INDEX列中
下面SQL只需要INDEX UNIQUE SCAN 操作
SELECT LODGING
FROM LODGING
WHERE LODGING =
索引范圍查詢(INDEX RANGE SCAN)
適用於兩種情況
例
SELECT LODGING FROM LODGING WHERE LODGING LIKE
WHERE子句條件包括一系列值
例
SELECT LODGING
FROM LODGING
WHERE MANAGER =
這個SQL的執行分兩步
由於SQL返回LODGING列
WHERE子句中
SELECT LODGING
FROM LODGING
WHERE MANAGER LIKE
基礎表(Driving Table)是指被最先訪問的表(通常以全表掃描的方式被訪問)
如果你使用的是CBO (COST BASED OPTIMIZER)
如果你用RBO (RULE BASED OPTIMIZER)
舉例
SELECT A
FROM WORKER A
LODGING B
WHERE A
由於LODGING表的LODING列上有一個索引
[NextPage]
當SQL語句的執行路徑可以使用分布在多個表上的多個索引時
在ORACLE選擇執行路徑時
如果不同表中兩個想同等級的索引將被引用
如果相同表中兩個想同等級的索引將被引用
舉例
DEPTNO上有一個非唯一性索引
SELECT ENAME
FROM EMP
WHERE DEPT_NO =
AND EMP_CAT =
這裡
TABLE ACCESS BY ROWID ON EMP
AND
INDEX RANGE SCAN ON DEPT_IDX
INDEX RANGE SCAN ON CAT_IDX
當WHERE子句中有索引列
舉例
DEPTNO上有一個非唯一性索引
SELECT ENAME
FROM EMP
WHERE DEPTNO >
AND EMP_CAT =
這裡只有EMP_CAT索引被用到
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON CAT_IDX
當ORACLE無法判斷索引的等級高低差別
舉例
DEPTNO上有一個非唯一性索引
SELECT ENAME
FROM EMP
WHERE DEPTNO >
AND EMP_CAT >
這裡
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON DEPT_IDX
譯者按
SQL> select index_name
INDEX_NAME UNIQUENES
EMPNO UNIQUE
EMPTYPE NONUNIQUE
SQL> select * from emp where empno >=
no rows selected
Execution Plan
雖然EMPNO是唯一性索引
From:http://tw.wingwit.com/Article/program/Oracle/201311/17830.html