我們要做到不但會(huì)寫(xiě)SQL,還要做到寫(xiě)出性能優(yōu)良的SQL,以下為筆者學(xué)習(xí)、摘錄、并匯總部分資料與大家分享!
(
1
)
?????
選擇
最有效率的表名
順
序
(
只在基于
規(guī)則
的
優(yōu)
化器中有效
)
:
ORACLE
的解析器按照從右到左的
順
序
處
理
FROM
子句中的表名,
FROM
子句中寫(xiě)在最后的表
(
基
礎(chǔ)
表
driving table)
將被最先
處
理,在
FROM
子句中包含多個(gè)表的情況下
,
你必
須選擇記錄
條數(shù)最少的表作
為
基
礎(chǔ)
表。如果有
3
個(gè)以上的表
連
接
查詢
,
那就需要
選擇
交叉表
(intersection table)
作
為
基
礎(chǔ)
表
,
交叉表是指那個(gè)被其他表所引用的表
.
(
2
)
?????
WHERE
子句中的
連
接
順
序.:
ORACLE
采用自下而上的
順
序解析
WHERE
子句
,
根據(jù)
這
個(gè)原理
,
表之
間
的
連
接必
須
寫(xiě)在其他
WHERE
條件之前
,
那些可以
過(guò)濾
掉最大數(shù)量
記錄
的條件必
須
寫(xiě)在
WHERE
子句的末尾
.
(
3
)
?????
SELECT
子句中避免使用
‘ * ‘
:
ORACLE
在解析的
過(guò)
程中
,
會(huì)將
'*'
依次
轉(zhuǎn)換
成所有的列名
,
這
個(gè)工作是通
過(guò)查詢
數(shù)據(jù)字典完成的
,
這
意味著將耗
費(fèi)
更多的
時(shí)間
(
4
)
?????
減少
訪問(wèn)
數(shù)據(jù)
庫(kù)
的次數(shù):
ORACLE
在內(nèi)部
執(zhí)
行了
許
多工作
:
解析
SQL
語(yǔ)
句
,
估算索引的利用率
,
綁
定
變
量
,
讀
數(shù)據(jù)
塊
等;
(
5
)
?????
在
SQL*Plus , SQL*Forms
和
Pro*C
中重新
設(shè)
置
ARRAYSIZE
參數(shù)
,
可以增加
每
次數(shù)據(jù)
庫(kù)訪問(wèn)
的
檢
索數(shù)據(jù)量
,
建
議值為
200
(
6
)
?????
使用
DECODE
函數(shù)來(lái)減少
處
理
時(shí)間
:
使用
DECODE
函數(shù)可以避免重
復(fù)掃
描相同
記錄
或重
復(fù)連
接相同的表
.
(
7
)
?????
整合
簡(jiǎn)單
,
無(wú)
關(guān)聯(lián)
的數(shù)據(jù)
庫(kù)訪問(wèn)
:
如果你有幾個(gè)
簡(jiǎn)單
的數(shù)據(jù)
庫(kù)查詢語(yǔ)
句
,
你可以把它
們
整合到一個(gè)
查詢
中
(
即使它
們
之
間
沒(méi)有
關(guān)
系
)
(
8
)
?????
刪
除重
復(fù)記錄
:
最高效的
刪
除重
復(fù)記錄
方法
(
因
為
使用了
ROWID)
例子:
DELETE ?FROM ?EMP E ?WHERE ?E.ROWID > (SELECT MIN(X.ROWID)
FROM ?EMP X ?WHERE ?X.EMP_NO = E.EMP_NO);
FROM ?EMP X ?WHERE ?X.EMP_NO = E.EMP_NO);
(
9
)
?????
用
TRUNCATE
替代
DELETE
:
當(dāng)
刪
除表中的
記錄時(shí)
,
在通常情況下
,
回
滾
段
(rollback segments )
用來(lái)存放可以被恢
復(fù)
的信息
.
如果你沒(méi)有
COMMIT
事
務(wù)
,ORACLE
會(huì)將數(shù)據(jù)恢
復(fù)
到
刪
除之前的狀
態(tài)
(
準(zhǔn)確地
說(shuō)
是恢
復(fù)
到
執(zhí)
行
刪
除命令之前的狀況
)
而當(dāng)運(yùn)用
TRUNCATE
時(shí)
,
回
滾
段不再存
放任何可被恢
復(fù)
的信息
.
當(dāng)命令運(yùn)行后
,
數(shù)據(jù)不能被恢
復(fù)
.
因此很少的
資
源被
調(diào)
用
,
執(zhí)
行
時(shí)間
也會(huì)很短
.
(
譯
者按
: TRUNCATE
只在
刪
除全表適用
,TRUNCATE
是
DDL
不是
DML)
(
10
)
?
盡量多使用
COMMIT
:
只要有可能
,
在程序中盡量多使用
COMMIT,
這樣
程序的性能得到提高
,
需求也會(huì)因
為
COMMIT
所
釋
放的
資
源而減少
:
COMMIT 所 釋 放的 資 源 :
a. 回 滾 段上用于恢 復(fù) 數(shù)據(jù)的信息 .
b. 被程序 語(yǔ) 句 獲 得的 鎖
c. redo log buffer 中的空 間
d. ORACLE 為 管理上述 3 種資 源中的內(nèi)部花 費(fèi)
COMMIT 所 釋 放的 資 源 :
a. 回 滾 段上用于恢 復(fù) 數(shù)據(jù)的信息 .
b. 被程序 語(yǔ) 句 獲 得的 鎖
c. redo log buffer 中的空 間
d. ORACLE 為 管理上述 3 種資 源中的內(nèi)部花 費(fèi)
(
11
)
?
用
Where
子句替
換
HAVING
子句:
避免使用
HAVING
子句
, HAVING
只會(huì)在
檢
索出所有
記錄
之后才
對(duì)結(jié)
果集
進(jìn)
行
過(guò)濾
.
這
個(gè)
處
理需要排序
,
總計(jì)
等操作
.
如果能通
過(guò)
WHERE
子句限制
記錄
的數(shù)目
,
那就能減少
這
方面的
開(kāi)銷(xiāo)
.
(
非
oracle
中
)
on
、
where
、
having
這
三個(gè)都可以加條件的子句中,
on
是最先
執(zhí)
行,
where
次之,
having
最后,因
為
on
是先把不符合條件的
記錄過(guò)濾
后才
進(jìn)
行
統(tǒng)計(jì)
,它就可以減少中
間
運(yùn)算要
處
理的數(shù)據(jù),按理
說(shuō)應(yīng)該
速度是最快的,
where
也
應(yīng)該
比
having
快點(diǎn)的,因
為
它
過(guò)濾
數(shù)據(jù)后才
進(jìn)
行
sum
,在兩個(gè)表
聯(lián)
接
時(shí)
才用
on
的,所以在一個(gè)表的
時(shí)
候,就剩下
where
跟
having
比
較
了。在
這單
表
查詢統(tǒng)計(jì)
的情況下,如果要
過(guò)濾
的條件沒(méi)有
涉
及到要
計(jì)
算字段,那它
們
的
結(jié)
果是一
樣
的,只是
where
可以使用
rushmore
技
術(shù)
,而
having
就不能,在速度上后者要慢如果要
涉
及到
計(jì)
算的字段,就表示在沒(méi)
計(jì)
算之前,
這
個(gè)字段的
值
是不確定的,根據(jù)上篇寫(xiě)的工作流程,
where
的作用
時(shí)間
是在
計(jì)
算之前就完成的,而
having
就是在
計(jì)
算后才起作用的,所以在
這種
情況下,兩者的
結(jié)
果會(huì)不同。在多表
聯(lián)
接
查詢時(shí)
,
on
比
where
更早起作用。系
統(tǒng)
首先根據(jù)各個(gè)表之
間
的
聯(lián)
接條件,把多個(gè)表合成一個(gè)
臨時(shí)
表后,再由
where
進(jìn)
行
過(guò)濾
,然后再
計(jì)
算,
計(jì)
算完后再由
having
進(jìn)
行
過(guò)濾
。由此可
見(jiàn)
,要想
過(guò)濾
條件起到正確的作用,首先要明白
這
個(gè)條件
應(yīng)該
在什
么時(shí)
候起作用,然后再?zèng)Q定放在那里
(
12
)
?
減少
對(duì)
表的
查詢
:
在含有子
查詢
的
SQL
語(yǔ)
句中
,
要特
別
注意減少
對(duì)
表的
查詢
.
例子:
????
SELECT
?TAB_NAME
FROM
TABLES
WHERE
(TAB_NAME,DB_VER) = (
SELECT
TAB_NAME,DB_VER?
FROM
?TAB_COLUMNS ?
WHERE
?VERSION = 604)
(
13
)
?
通
過(guò)
內(nèi)部函數(shù)提高
SQL
效率
.
:
復(fù)雜
的
SQL
往往
犧
牲了
執(zhí)
行效率
.
能
夠
掌握上面的運(yùn)用函數(shù)解決
問(wèn)題
的方法在
實(shí)際
工作中是非常有意
義
的
(
14
)
?
使用表的
別
名
(Alias)
:
當(dāng)在
SQL
語(yǔ)
句中
連
接多個(gè)表
時(shí)
,
請(qǐng)
使用表的
別
名并把
別
名前
綴
于
每
個(gè)
Column
上
.
這樣
一來(lái)
,
就可以減少解析的
時(shí)間
并減少那些由
Column
歧
義
引起的
語(yǔ)
法
錯(cuò)誤
.
(
15
)
?
用
EXISTS
替代
IN
、用
NOT EXISTS
替代
NOT IN
:
在
許
多基于基
礎(chǔ)
表的
查詢
中
,
為
了
滿
足一個(gè)條件
,
往往需要
對(duì)
另一個(gè)表
進(jìn)
行
聯(lián)
接
.
在
這種
情況下
,
使用
EXISTS(
或
NOT EXISTS)
通常將提高
查詢
的效率
.
在子
查詢
中
,NOT IN
子句將
執(zhí)
行一個(gè)內(nèi)部的排序和合并
.
無(wú)
論
在哪
種
情況下
,NOT IN
都是最低效的
(
因
為
它
對(duì)
子
查詢
中的表
執(zhí)
行了一個(gè)全表遍
歷
).
為
了避免使用
NOT IN ,
我
們
可以把它改寫(xiě)成外
連
接
(Outer Joins)
或
NOT EXISTS.
例子:
(
高效
)
SELECT
*
FROM
?EMP (
基
礎(chǔ)
表
) ?
WHERE
?EMPNO > 0 ?
AND
?
EXISTS
(
SELECT
‘X' ?
FROM
DEPT ?
WHERE
?DEPT.DEPTNO = EMP.DEPTNO ?
AND
?LOC = ‘MELB')
(
低效
)
SELECT
?*
FROM
?EMP (
基
礎(chǔ)
表
) ?
WHERE
?EMPNO > 0 ?
AND
?DEPTNO
IN
(SELECT
DEPTNO ?
FROM
?DEPT ?
WHERE
?LOC = ‘MELB'
)
(
16
)
?
識(shí)別
'
低效
執(zhí)
行
'
的
SQL
語(yǔ)
句:
雖
然目前各
種關(guān)
于
SQL
優(yōu)
化的
圖
形化工具
層
出不
窮
,
但是寫(xiě)出自己的
SQL
工具來(lái)解決
問(wèn)題
始
終
是一個(gè)最好的方法:
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 ?EXECUTIONS>0
AND ?BUFFER_GETS > 0
AND ?(BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY ? 4 DESC ;
ROUND ((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2 ) Hit_radio,
ROUND (DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM ?V$SQLAREA
WHERE ?EXECUTIONS>0
AND ?BUFFER_GETS > 0
AND ?(BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY ? 4 DESC ;
(
17
)
?
用索引提高效率:
索引是表的一個(gè)概念部分
,
用來(lái)提高
檢
索數(shù)據(jù)的效率,
ORACLE
使用了一個(gè)
復(fù)雜
的自平衡
B-tree
結(jié)
構(gòu)
.
通常
,
通
過(guò)
索引
查詢
數(shù)據(jù)比全表
掃
描要快
.
當(dāng)
ORACLE
找出
執(zhí)
行
查詢
和
Update
語(yǔ)
句的最佳路徑
時(shí)
, ORACLE
優(yōu)
化器將使用索引
.
同
樣
在
聯(lián)結(jié)
多個(gè)表
時(shí)
使用索引也可以提高效率
.
另一個(gè)使用索引的好
處
是
,
它提供了主
鍵
(primary key)
的唯一性
驗(yàn)證
.
。那些
LONG
或
LONG RAW
數(shù)據(jù)
類
型
,
你可以索引幾乎所有的列
.
通常
,
在大型表中使用索引特
別
有效
.
當(dāng)然
,
你也會(huì)
發(fā)現(xiàn)
,
在
掃
描小表
時(shí)
,
使用索引同
樣
能提高效率
.
雖
然使用索引能得到
查詢
效率的提高
,
但是我
們
也必
須
注意到它的代價(jià)
.
索引需要空
間
來(lái)存
儲(chǔ)
,
也需要定期
維護(hù)
,
每
當(dāng)有
記錄
在表中增減或索引列被修改
時(shí)
,
索引本身也會(huì)被修改
.
這
意味著
每
條
記錄
的
INSERT , DELETE , UPDATE
將
為
此多付出
4 , 5
次的磁
盤(pán)
I/O .
因
為
索引需要
額
外的存
儲(chǔ)
空
間
和
處
理
,
那些不必要的索引反而會(huì)使
查詢
反
應(yīng)時(shí)間變
慢
.
。
定期的重構(gòu)索引是有必要的
.
:
ALTER
?
INDEX
<INDEXNAME>
REBUILD
<TABLESPACENAME>
(
18
)
?
用
EXISTS
替
換
DISTINCT
:
當(dāng)提交一個(gè)包含一
對(duì)
多表信息
(
比如部
門(mén)
表和雇
員
表
)
的
查詢時(shí)
,
避免在
SELECT
子句中使用
DISTINCT.
一般可以考
慮
用
EXIST
替
換
, EXISTS
使
查詢
更
為
迅速
,
因
為
RDBMS
核心模
塊
將在子
查詢
的條件一旦
滿
足后
,
立刻返回
結(jié)
果
.
例子:
??????
(
低效
):
SELECT ? DISTINCT ?DEPT_NO,DEPT_NAME ? FROM ?DEPT D , EMP E
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 ) ;
( 高效 ):
SELECT ?DEPT_NO,DEPT_NAME ? FROM ?DEPT D ? WHERE ? EXISTS ( SELECT ‘X'
FROM ?EMP E ? WHERE ?E.DEPT_NO = D.DEPT_NO ) ;
(
19
)
?
sql
語(yǔ)
句用大寫(xiě)的
;因
為
oracle
總
是先解析
sql
語(yǔ)
句,把小寫(xiě)的字母
轉(zhuǎn)換
成大寫(xiě)的再
執(zhí)
行
(
20
)
?
在
java
代
碼
中盡量
少用
連
接符
“
+
”
連
接字符串
!
(
21
)
?
避免在索引列上使用
NOT
通常
,
我
們
要避免在索引列上使用
NOT, NOT
會(huì)
產(chǎn)
生在和在索引列上使用函數(shù)相同的影響
.
當(dāng)
ORACLE”
遇到
”NOT,
他就會(huì)停止使用索引
轉(zhuǎn)
而
執(zhí)
行全表
掃
描
.
(
22
)
?
避免在索引列上使用
計(jì)
算.
WHERE 子句中,如果索引列是函數(shù)的一部分. 優(yōu) 化器將不使用索引而使用全表 掃 描.
舉 例 :
低效:
SELECT … FROM ?DEPT ?WHERE SAL * 12 > 25000;
高效 :
SELECT … FROM DEPT WHERE SAL > 25000/12;
WHERE 子句中,如果索引列是函數(shù)的一部分. 優(yōu) 化器將不使用索引而使用全表 掃 描.
舉 例 :
低效:
SELECT … FROM ?DEPT ?WHERE SAL * 12 > 25000;
高效 :
SELECT … FROM DEPT WHERE SAL > 25000/12;
(
23
)
?
用
>=
替代
>
高效
:
SELECT * FROM ?EMP ?WHERE ?DEPTNO >=4
低效 :
SELECT * FROM EMP WHERE DEPTNO >3
兩者的區(qū) 別 在于 , 前者 DBMS 將直接跳到第一個(gè) DEPT 等于 4 的 記錄 而后者將首先定位到 DEPTNO=3 的 記錄 并且向前 掃 描到第一個(gè) DEPT 大于 3 的 記錄 .
SELECT * FROM ?EMP ?WHERE ?DEPTNO >=4
低效 :
SELECT * FROM EMP WHERE DEPTNO >3
兩者的區(qū) 別 在于 , 前者 DBMS 將直接跳到第一個(gè) DEPT 等于 4 的 記錄 而后者將首先定位到 DEPTNO=3 的 記錄 并且向前 掃 描到第一個(gè) DEPT 大于 3 的 記錄 .
(
24
)
?
用
UNION
替
換
OR (
適用于索引列
)
通常情況下
,
用
UNION
替
換
WHERE
子句中的
OR
將會(huì)起到
較
好的效果
.
對(duì)
索引列使用
OR
將造成全表
掃
描
.
注意
,
以上
規(guī)則
只
針對(duì)
多個(gè)索引列有效
.
如果有
column
沒(méi)有被索引
,
查詢
效率可能會(huì)因
為
你沒(méi)有
選擇
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”
如果你 堅(jiān) 持要用 OR, 那就需要返回 記錄 最少的索引列寫(xiě)在最前面 .
高效 :
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”
如果你 堅(jiān) 持要用 OR, 那就需要返回 記錄 最少的索引列寫(xiě)在最前面 .
(
25
)
?
用
IN
來(lái)替
換
OR ?
這
是一條
簡(jiǎn)單
易
記
的
規(guī)則
,但是
實(shí)際
的
執(zhí)
行效果
還須檢驗(yàn)
,在
ORACLE8i
下,兩者的
執(zhí)
行路徑似乎是相同的.
低效
:
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);
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);
(
26
)
?
避免在索引列上使用
IS NULL
和
IS NOT NULL
避免在索引中使用任何可以
為
空的列,
ORACLE
將無(wú)法使用
該
索引.
對(duì)
于
單
列索引,如果列包含空
值
,索引中將不存在此
記錄
.
對(duì)
于
復(fù)
合索引,如果
每
個(gè)列都
為
空,索引中同
樣
不存在此
記錄
.
如果至少有一個(gè)列不
為
空,
則記錄
存在于索引中.
舉
例
:
如果唯一性索引建立在表的
A
列和
B
列上
,
并且表中存在一條
記錄
的
A,B
值為
(123,null) , ORACLE
將不接受下一條具有相同
A,B
值
(
123,null
)的
記錄
(
插入
).
然而如果所有的索引列都
為
空,
ORACLE
將
認(rèn)為
整個(gè)
鍵值為
空而空不等于空
.
因此你可以插入
1000
條具有相同
鍵值
的
記錄
,
當(dāng)然它
們
都是空
!
因
為
空
值
不存在于索引列中
,
所以
WHERE
子句中
對(duì)
索引列
進(jìn)
行空
值
比
較
將使
ORACLE
停用
該
索引
.
低效
: (
索引失效
)
SELECT … FROM ?DEPARTMENT ? WHERE ?DEPT_CODE IS NOT NULL ;
高效 : ( 索引有效 )
SELECT … FROM ?DEPARTMENT ? WHERE ?DEPT_CODE >= 0;
SELECT … FROM ?DEPARTMENT ? WHERE ?DEPT_CODE IS NOT NULL ;
高效 : ( 索引有效 )
SELECT … FROM ?DEPARTMENT ? WHERE ?DEPT_CODE >= 0;
(
27
)
?
總
是使用索引的第一個(gè)列:
如果索引是建立在多個(gè)列上
,
只有在它的第一個(gè)列
(leading column)
被
where
子句引用
時(shí)
,
優(yōu)
化器才會(huì)
選擇
使用
該
索引
.
這
也是一條
簡(jiǎn)單
而重要的
規(guī)則
,當(dāng)
僅
引用索引的第二個(gè)列
時(shí)
,
優(yōu)
化器使用了全表
掃
描而忽略了索引
(
28
)
?
用
UNION-ALL
替
換
UNION (
如果有可能的
話
)
:
當(dāng)
SQL
語(yǔ)
句需要
UNION
兩個(gè)
查詢結(jié)
果集合
時(shí)
,
這
兩個(gè)
結(jié)
果集合會(huì)以
UNION-ALL
的方式被合并
,
然后在
輸
出最
終結(jié)
果前
進(jìn)
行排序
.
如果用
UNION ALL
替代
UNION,
這樣
排序就不是必要了
.
效率就會(huì)因此得到提高
.
需要注意的是
,
UNION ALL
將重
復(fù)輸
出兩個(gè)
結(jié)
果集合中相同
記錄
.
因此各位
還
是要從
業(yè)務(wù)
需求分析使用
UNION ALL
的可行性
.
UNION
將
對(duì)結(jié)
果集合排序
,
這
個(gè)操作會(huì)使用到
SORT_AREA_SIZE
這塊
內(nèi)存
.
對(duì)
于
這塊
內(nèi)存的
優(yōu)
化也是相當(dāng)重要的
.
下面的
SQL
可以用來(lái)
查詢
排序的消耗量
低效:
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'
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'
(
29
)
?
用
WHERE
替代
ORDER BY
:
ORDER BY
子句只在兩
種嚴(yán)
格的條件下使用索引
.
ORDER BY 中所有的列必 須 包含在相同的索引中并保持在索引中的排列 順 序 .
ORDER BY 中所有的列必 須 定 義為 非空 .
WHERE 子句使用的索引和 ORDER BY 子句中所使用的索引不能并列 .
ORDER BY 中所有的列必 須 包含在相同的索引中并保持在索引中的排列 順 序 .
ORDER BY 中所有的列必 須 定 義為 非空 .
WHERE 子句使用的索引和 ORDER BY 子句中所使用的索引不能并列 .
例如
:
表 DEPT 包含以下列 :
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
表 DEPT 包含以下列 :
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效
: (
索引不被使用
)
SELECT DEPT_CODE? FROM ?DEPT ? ORDER BY ?DEPT_TYPE
高效 : ( 使用索引 )
SELECT DEPT_CODE ? FROM ?DEPT ? WHERE ?DEPT_TYPE > 0
SELECT DEPT_CODE? FROM ?DEPT ? ORDER BY ?DEPT_TYPE
高效 : ( 使用索引 )
SELECT DEPT_CODE ? FROM ?DEPT ? WHERE ?DEPT_TYPE > 0
(
30
)
?
避免改
變
索引列的
類
型
.:
當(dāng)比
較
不同數(shù)據(jù)
類
型的數(shù)據(jù)
時(shí)
, ORACLE
自
動(dòng)對(duì)
列
進(jìn)
行
簡(jiǎn)單
的
類
型
轉(zhuǎn)換
.
假
設(shè)
EMPNO
是一個(gè)數(shù)
值類
型的索引列
.
SELECT … ? FROM EMP ? WHERE ? EMPNO = ‘123'
實(shí)際 上 , 經(jīng)過(guò) ORACLE 類 型 轉(zhuǎn)換 , 語(yǔ) 句 轉(zhuǎn) 化 為 :
SELECT … ? FROM EMP ?WHERE ?EMPNO = TO_NUMBER(‘123')
幸運(yùn)的是 , 類 型 轉(zhuǎn)換 沒(méi)有 發(fā) 生在索引列上 , 索引的用途沒(méi)有被改 變 .
現(xiàn) 在 , 假 設(shè) EMP_TYPE 是一個(gè)字符 類 型的索引列 .
SELECT … ? FROM EMP ? WHERE EMP_TYPE = 123
這 個(gè) 語(yǔ) 句被 ORACLE 轉(zhuǎn)換為 :
SELECT … ? FROM EMP ? WHERETO_NUMBER(EMP_TYPE)=123
因 為 內(nèi)部 發(fā) 生的 類 型 轉(zhuǎn)換 , 這 個(gè)索引將不會(huì)被用到 ! 為 了避免 ORACLE 對(duì) 你的 SQL 進(jìn) 行 隱 式的 類 型 轉(zhuǎn)換 , 最好把 類 型 轉(zhuǎn)換 用 顯 式表 現(xiàn) 出來(lái) . 注意當(dāng)字符和數(shù) 值 比 較時(shí) , ORACLE 會(huì) 優(yōu) 先 轉(zhuǎn)換 數(shù) 值類 型到字符 類 型
SELECT … ? FROM EMP ? WHERE ? EMPNO = ‘123'
實(shí)際 上 , 經(jīng)過(guò) ORACLE 類 型 轉(zhuǎn)換 , 語(yǔ) 句 轉(zhuǎn) 化 為 :
SELECT … ? FROM EMP ?WHERE ?EMPNO = TO_NUMBER(‘123')
幸運(yùn)的是 , 類 型 轉(zhuǎn)換 沒(méi)有 發(fā) 生在索引列上 , 索引的用途沒(méi)有被改 變 .
現(xiàn) 在 , 假 設(shè) EMP_TYPE 是一個(gè)字符 類 型的索引列 .
SELECT … ? FROM EMP ? WHERE EMP_TYPE = 123
這 個(gè) 語(yǔ) 句被 ORACLE 轉(zhuǎn)換為 :
SELECT … ? FROM EMP ? WHERETO_NUMBER(EMP_TYPE)=123
因 為 內(nèi)部 發(fā) 生的 類 型 轉(zhuǎn)換 , 這 個(gè)索引將不會(huì)被用到 ! 為 了避免 ORACLE 對(duì) 你的 SQL 進(jìn) 行 隱 式的 類 型 轉(zhuǎn)換 , 最好把 類 型 轉(zhuǎn)換 用 顯 式表 現(xiàn) 出來(lái) . 注意當(dāng)字符和數(shù) 值 比 較時(shí) , ORACLE 會(huì) 優(yōu) 先 轉(zhuǎn)換 數(shù) 值類 型到字符 類 型
(
31
)
?
需要當(dāng)心的
WHERE
子句
:
某些
SELECT
語(yǔ)
句中的
WHERE
子句不使用索引
.
這
里有一些例子
.
在下面的例子里 , (1) ‘!=' 將不使用索引 . 記 住 , 索引只能告 訴 你什 么 存在于表中 , 而不能告 訴 你什 么 不存在于表中 . (2) ‘||' 是 字符 連 接函數(shù) . 就象其他函數(shù)那 樣 , 停用了索引 . (3) ‘+' 是數(shù)學(xué)函數(shù) . 就象其他數(shù)學(xué)函數(shù)那 樣 , 停用了索引 . (4) 相同的索引列不能互相比 較 , 這 將會(huì)啟用全表 掃 描 .
在下面的例子里 , (1) ‘!=' 將不使用索引 . 記 住 , 索引只能告 訴 你什 么 存在于表中 , 而不能告 訴 你什 么 不存在于表中 . (2) ‘||' 是 字符 連 接函數(shù) . 就象其他函數(shù)那 樣 , 停用了索引 . (3) ‘+' 是數(shù)學(xué)函數(shù) . 就象其他數(shù)學(xué)函數(shù)那 樣 , 停用了索引 . (4) 相同的索引列不能互相比 較 , 這 將會(huì)啟用全表 掃 描 .
(
32
)
?
a.
如果
檢
索數(shù)據(jù)量超
過(guò)
30%
的表中
記錄
數(shù)
.
使用索引將沒(méi)有
顯
著的效率提高
.
b. 在特定情況下 , 使用索引也 許 會(huì)比全表 掃 描慢 , 但 這 是同一個(gè)數(shù)量 級(jí) 上的區(qū) 別 . 而通常情況下 , 使用索引比全表 掃 描要 塊 幾倍乃至幾千倍 !
b. 在特定情況下 , 使用索引也 許 會(huì)比全表 掃 描慢 , 但 這 是同一個(gè)數(shù)量 級(jí) 上的區(qū) 別 . 而通常情況下 , 使用索引比全表 掃 描要 塊 幾倍乃至幾千倍 !
(
33
)
?
避免使用耗
費(fèi)資
源的操作
:
帶
有
DISTINCT,UNION,MINUS,INTERSECT,ORDER BY
的
SQL
語(yǔ)
句會(huì)啟
動(dòng)
SQL
引擎
執(zhí) 行耗 費(fèi)資 源的排序 (SORT) 功能 . DISTINCT 需要一次排序操作 , 而其他的至少需要 執(zhí) 行兩次排序 . 通常 , 帶 有 UNION, MINUS , INTERSECT 的 SQL 語(yǔ) 句都可以用其他方式重寫(xiě) . 如果你的數(shù)據(jù) 庫(kù) 的 SORT_AREA_SIZE 調(diào) 配得好 , 使用 UNION , MINUS, INTERSECT 也是可以考 慮 的 , 畢 竟它 們 的可 讀 性很 強(qiáng)
執(zhí) 行耗 費(fèi)資 源的排序 (SORT) 功能 . DISTINCT 需要一次排序操作 , 而其他的至少需要 執(zhí) 行兩次排序 . 通常 , 帶 有 UNION, MINUS , INTERSECT 的 SQL 語(yǔ) 句都可以用其他方式重寫(xiě) . 如果你的數(shù)據(jù) 庫(kù) 的 SORT_AREA_SIZE 調(diào) 配得好 , 使用 UNION , MINUS, INTERSECT 也是可以考 慮 的 , 畢 竟它 們 的可 讀 性很 強(qiáng)
(
34
)
?
優(yōu)
化
GROUP BY:
提高
GROUP BY
語(yǔ)
句的效率
,
可以通
過(guò)
將不需要的
記錄
在
GROUP BY
之前
過(guò)濾
掉
.
下面兩個(gè)
查詢
返回相同
結(jié)
果但第二個(gè)明
顯
就快了
許
多
.
低效
:
SELECT JOB , AVG(SAL)
FROM EMP
GROUP JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
高效 :
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP JOB
?
SELECT JOB , AVG(SAL)
FROM EMP
GROUP JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
高效 :
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP JOB
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

