關于SQL優化我提提幾點總結,這里沒有具體的實例,假如大家有愛好,可以把他貼上來
1.除非寫頻率很低,否則不要用RAID5,但是對于cache能夠減少RAID5的負荷
2.對于一個chained fetch ratio的,建議需要用一個高的pctfree來rebuild table
3.假如你有一個很高的磁盤排序率,那么建議修改sort_area_size,將其增大
4.buffer busy waits經常是由于很頻繁的insert ,需要重建,或者沒有充足的回滾段引起的
還應觀注一下event這列其他值,這是我們調優的要害一列,下面對常出現的event做以簡要的說明:
free buffer waits這個參數所標識是dbwr是否夠用的問題,與IO很大相關的,
當v$session_wait中的free buffer wait的條目很小或沒有的時侯,說明你的系統的dbwr進程決對夠用,
不用調整;free buffer wait的條目很多,你的系統感覺起來一定很慢,這時說明你的dbwr已經不夠用了,
它產生的wio已經成為你的數據庫性能的瓶頸,這時的解決辦法如下:
a.1增加寫進程,同時要調整 db_block_lru_latches 參數
示例:修改或添加如下兩個參數
db_writer_PRocesses=4
db_block_lru_latches=8
a.2開異步IO,IBM這方面簡單得多,hp則麻煩一些,可以與Hp工程師聯系。
5.遞歸SQL
為了決定所有表和列在SQL中的名字是否正確,Oracle必須通過數據字典檢查有效性,這些信息通常在內存中(ROW CACHE)
找到了,但是假如在內存中找不到,那么就需要要進行遞歸SQL
6.在不改變源代碼的前提下,可以通過兩個參數調整來減少解析
cursor_sharing
session_cached_cursors
7.open cursor通常意義上僅是得到一個handle,但在某些情況下不是。
open cursor只是簡單的定位首記錄的指針
8.創建新表后,高水位為第5塊
9.hash join
假如整個hash表能夠填充到內存,將很好,否則就需要臨時表來進行分配。
所以hash join經常對于兩個不同大小的表進行連接,也可以在并行模式和反向連接中工作的很好
10.存儲概要能夠幫助從一個低版本移植到高版本,也可以將RULE移植到COST
11.OR經常可以利用union來實現索引的使用,當然ORACLE優化器有時也會自動進行轉換
12.經常被> <等操作的列都要在可能的情況下使用索引
13.葉塊包含了上一塊和下一塊的指針,所以答應對于索引過的列,使用order by和使用> <等操作進行利用
另外,對于索引掃描,即使沒有任何記錄,也會有3-4個IO,因為有縱向SCAN
對于大表,深度為4(1個都塊,2級分支塊和葉塊),但是經常頭塊和分支塊通常都會在內存,所以只會有1到2個物理讀塊
14.索引鍵值分離是很昂貴的,對于使用插入增量序列的值,可以避免索引分離
15.不能壓縮分區索引和位圖索引
16.唯一索引或者主鍵經常是很好的hash key,因為hash key不適合區域掃描
17.由于普通的B樹索引,仍然消耗了很大磁盤空間,并且insert update delete也同樣有很大的負載,所以考慮采用IOT,這樣就沒有表了,索引本身就是表,但是結構可是索引結構。主鍵將和所有列存儲在葉節點,這樣就造成了可能對索引結構的性能下降,所以可以通過設置including 來將某些不常用的大字段列放到益出段,對于想BOLB字段,可以采用disable storage in row使得分離不常查詢的BOLB字段分離到別的段和表空間
18.query+current為邏輯讀
autotrace沒有每一步的row count,也不包括cpu or elapsed times
19.對于綁定變量與直方圖的選擇
條件 綁定 直方圖
---------------------------- ------------------- -----------------------
搜索值不變 不需要 可能需要
range scan 不需要 需要
執行精確查找,
但有些值分布很少 不需要 需要
這個SQL執行很頻繁,
期望快速執行 需要 不需要
用戶特定使用的
復雜的SQL 可能不需要,因為最終 需要
用戶可能不喜歡
20.對于有null值的列要建立索引,那么最好使用default(where改成默認值),并設置not null
21.hash cluster能提高精確匹配,但不能在range scan中得到好處
22.你可以分離表中頻繁被訪問的和不頻繁被訪問的列到不同的段中或者表中,來提高性能,假如是IOT,可以使用INCLUDING
23. 范圍搜索有時用PLSQL也是很好的,比如找到MAX和MIN值
24.優化位圖索引,bitmap_merge_area_size 和 minimize records_per_block (該參數還可以優化pctfree)
minimize records_per_block能減少索引大小,但對全表掃描有副作用,他能造成塊數的增長
25.reset 高水位
move table
eXP + truncate table + imp
ctas
HWM 和 direct insert 有關系,direct insert 是從HWM 位置開始分配新的block 而不會使用HWM 以下的即使可以使用的block
26.假如pctfree很小,那么可以考慮增長initrans在ctas中,假如pctfree=0,那么可能一個事務提出請求時已經添滿了塊,那么象UPDATE等在多SESSION操作時就會失敗。
所以,一個表被頻繁的表掃描,那么確保pctfree不要太高,非凡是在沒有UPDATE的情況下
27.多塊讀
在WINNT和2000中,多塊讀不能超過128K(32bit),所以最多是16個多塊讀在大多數UNIX文件系統中(不是RAW)是64K-1M
28.并行查詢
滿足下面條件:
有多個CPU
有剩余的CPU
數據分離在多個磁盤上
29.對于以響應時間為目標的,那么就要注重for update和order by操作,因為他們很難以first row方式優化
30.nested loop響應時間較好
32.hash_multiblock_io_count
該參數為影響的hash bUCket數,這個值大,可以減少hash bucket數對于很大的表,可以通過減低hash_multiblock_io_count來增加bucket數來提高性能
33.盡管cluster是提供了優化的選項,但是在真實環境是很少用的,假如對于非常頻繁的JOIN的可能有很大的提高性能,但通常是很傷害性能的
34.star hint可以將維度表進行笛卡兒積join,而事實表可以經過組合索引
35.不要期望使用多個位圖索引來替換組合索引提高性能
36.對于自join的SQL語句使用PLSQL可能更有效
因為可以通過PLSQL的某些變量的處理方式,而不用多次訪問同一個表
37.假如你有一個exists子查詢,而且子查詢沒有能使用索引,那么你就可以使用semijoin來提高性能
38.一個in子查詢,只是會執行一次,而exists子查詢是對于父查詢中的每行執行一次
假如IN子查詢不能通過子查詢中有索引來提高性能,那么exists能
假如exists不能通過父查詢中的索引來提高性能,那么in可以
39.不要總是設置always_semi_join為true,那樣的話,可能對于不需要semi join也會使用該連接
40.假如磁盤排序需要,每個排序進程都將分配自己的臨時段在臨時表空間中
當使用并行查詢,假如有很高的CPU負載,那么將會有很大的風險
41.記住索引全掃描可能并不比全表掃描一定有效,因為他不能想全表掃描那樣可以利用多塊讀,而且還可以采用并行
42.并行進程能夠將SQL執行分散成多個任務
每個任務通過使用不同的CPU會有對應的從進程去并行處理
(一個進程是一個擁有自己內存的執行單元,一個線程是在進程內的不同線程共享內存的執行單元)
43.并行執行只是在全表處理或者分區及在分區表中執行本地索引時用到
如:全表掃描
rebuild index
update (全表或分區表)
insert的并行子查詢
本地索引使用
批量插入,象SQLLDR
創建臨時表
比如我們執行
select /*+ parallel(c1 ,2) */
con...
...
from customers c1
order by ...
process a process b
fetch rows from fetch rows from
customers customers
process c process d
sort rows(a-k) sort rows(l-z)
combine rows
return result set
這里我們看到這個進程分散成4個進程,排序中各負責a-k和l-z,這樣就可以并行處理
我們在分區表中,也可以用一個并行從進程對應一個分區表
假如你的并行度是3,那么你可能就比普通的執行速度提高3倍
注重在單CPU下,假如使用并行,那么就可能造成性能下降,而且也要設置合適的并行度
并行適合對于長時間運行的語句
在oltp可能并不適合使用并行處理,因為事務并發比較多,每個用戶都要使用CPU,CPU的負載本來就比較高
所以并行處理還是比較適合olap中的批量導入,sqlldr,mis report和oltp中rebuild index
可以通過sar -u看cpu使用情況
44.并行度的設置
ORACLE通常設置兩個并行處理進程集,假如語句有scan、group by 和order by,那么需要3個并行處理集,但是
由于scan并行進程已經用完,所以可以重用。
select /*+ parallel(s,2) */ customer_id,sum(sale_value)
from sales s
group by customer_id
order by 2
-----scan------ --sort group by-- --sort order by --這里被重用了
parallel process 1 parallel process 3 parallel process 1
sales
table
parallel process 2 parallel process 4 parallel process 2
注重:并行從進程不會多于并行度的2倍
比如前面假設并行度為2,那么2*2=4個從進程
相關的參數
parallel_threads_per_cpu
這個是系統默認的并行度,假如建表的屬性設置了并行度,那么在使用該表全表掃描時使用并行方式
假如沒有指定,但是在SQL語句中加了并行提示,在沒有寫并行度的情況下使用系統有個默認并行度
使用v$pq_tqstat視圖連接并行計劃的細節
在一些復雜的并行SQL語句,確保所有重要的步驟在并行下執行很重要,這樣不至于由于某一步變成串行,而使并行的優勢丟失
45.假如有not in到自己的查詢,那么使用antijoin可以改善性能,并能使用并行
46.union可以使用并行
minux和intersect不能使用并行
47.當位圖索引被更新時,會產生全表行級鎖,所以在oltp強烈建議不要使用
48.假如刪除增加了系統的負載,那么可以采用邏輯刪除的方式,比如設置一個刪除列,更新該列
49.直接sqlldr
這種模型可以答應將數據塊構件在內存中,并且直接插入數據到數據文件
而通常模型是要經過buffer cache in sga 和dbwr
并且直接創建新的塊,就算free space存在也不使用
假如是分區表,那么能夠插入數據到高水位以上的取
假如是非分區表,那么新的區必須生成,那么假如有2個并行度,就必須先新建2個新的分區。
所以直接sqlldr可能影響全表掃描的性能
另外他也不支持外鍵參考,約束,觸發器,復制,IOT,LOB等
當內存buffer cache產生沖突或者數據庫寫產生瓶徑,那么對于傳統的INSERT就可能造成等待,可以考慮直接LOAD
假如支持異步IO,那么直接模式可以同時插入到多個數據文件
插入可以并行的運行在分區或未分區的表,但是UPDATE和DELETE只能運行在分區表
50.提交頻率要盡量的少
51.分區索引也可以在非分區表中
52.不要建立全局位圖索引,也不要建立分區位圖索引和cluster table
53.hash 分區的個數是2的乘方
54.snapshot存在快照日志,而只要數據庫有任何變動,都會記錄到快照日志中
有兩種刷新方法
fast refresh 和 complete refreshes
假如源表有很頻繁的更新,那么fast refresh 可能沒有complete refreshes更有效
假如變動比較小,對快照日志的負載也較小,就可以使用fast refresh
批量load時,可以先drop snapshot,然后load,create snapshot
55.物化視圖
基于事務刷新on commit
基于時間間隔on demand
56.觸發器
假如能使用after觸發器的盡量用after,因為before,觸發器執行前他會先鎖住觸發器表的行
57.java提供更好的算術運算
plsql偏向于數據庫敏感類型的,比如數據庫的類型操作啊,假如是java,那么由于類型不匹配而增加了轉換工作
58.sequence 中order 主要在ops和rac中使用
59.假如SQL語句中有系統視圖,那么由于系統視圖沒有統計信息,所以優化程序不知道執行的驅動順序,所以要使用象ordered這樣的提示
60.natural key是由多個有意義的字段組成
artificial key通常由序列號生成,他不需要更新,減少了鎖沖突,而且索引也較小,是比較好的選擇
63.異步IO對于WIN總是有效,而UNIX經常使用RAW設備情況下使用異步IO
64.對于多表聯接的優化
1).explain plan for
select ....;
set pagesize 0
set linesize 130
select * from table(dbms_xplan.display);
2).看看評估的結果,查看多表連接的方式,誰是驅動表,是否使用索引,返回的數據集大小決定是否需要使用hash_join
對于復雜的應用,你可以指定
alter session set workarea_size_policy = manual;
alter session set hash_area_size=???一個合理的值; --通常設置比初始化參數大
alter session set sort_area_size=???
3).不要在客戶段執行,通過設置sqlnet.ora可以避免通過net8這一層,直接在服務器上執行,減少客戶連接傳輸消耗的時間和資源
假如是客戶段連接,可能設置更大的sdu,tdu(不能超過最大值),及相應的arraysize大小.
4).多表聯接的優化原則是:
對性能產生影響最大的是表的驅動順序,他會影響到執行計劃和索引的使用
驅動表的選擇原則:
4.1)在選擇驅動表的時候盡量先選擇返回結果集最小的表作為驅動表(假如是hashjoin,那么會用他建立hash表),
然后選擇跟另一個表進行join會得到最小集合的表進行join,依次類推
例如from t1,t2,t3,t4 where ....
oracle會根據user_tables等表中的信息及where過濾條件分析出返回最少數據集的第一個驅動表是誰(比如t1),
然后分析,下一個與之join的表,通常選擇:
.where條件中這兩個表有直接關聯的字段(否則看執行計劃就會看到類似于MERGE JOINCARTESIAN,這就是笛卡兒積),
.找出與之關聯后返回的結果集最小的那個表
.....
4.2交叉表
假如是三個表join同一個字段,如t1.c1 = t2.c1 and t2.c1 =t3.c1,那么交叉表就是t2,因為t2出現了兩次,
這個交叉表的選擇是個要害,ORACLE會把交叉表作為驅動表,所以我們優化的原則的交叉表盡量的小,在交叉表中約束條件盡量的多,以使該交叉表返回的記錄集盡量的小
附加條件(除去連接本身),在連接相同的列,附加條件有些時候列上的索引會被限制住
比如 where t1.id = t2.id and t2.id =1111.那么附加條件在t2表上,并將其作為驅動表
4.3外連接的表
對于有外連接的表好象應該盡量作為最后驅動的表
4.4假如自己根據explain plan for后,
并結合應用,及豐富的優化的經驗的話,就可以針對某個應用增加提示 (可能的話可以設置存儲概要)
相關的主要提示有ordered(這個用處非常大,他也可以節省下oracle去分析誰是驅動表的過程了),index相關的提示(會影響驅動表的選擇),full,use_hash、user_nl...等很多,會影響到join順序
5). keep一下小表對象
6).另外可以通過建立索引,對于查少量列的盡量創建索引使其走index_ffs,假如有多個索引,想使用index_ffs,可以產生mergeindex_ffs
7). 另外非長有用的幾個提示是driving_site,richs_secret_hint
8).注重,假如有子查詢或者視圖,就非凡要注重是否能把外面的條件merge到視圖和子查詢里