高級SQL優化(一)

SQL優化簡介
一般在應用中, 糟糕的SQL語句是造成系統性能低下的最主要原因,例如大小寫的不統一、同樣的SQL語句不同的寫法等。而且,隨着數據量的增加,情況會變得越來越嚴重。(題外話:優秀的Oracle數據庫優化人才,是任何公司都稀缺的)
  SQL優化又稱SQL調節,其步驟一般包括:
 
SQL調節的目標
 
SQL調節包括三大目標:降低負載、均衡負載和並行化負載。
 
l降低負載:即尋找更高效的途徑來完成相同的功能
如某個非大表(小於2000萬行數據數據或小於2G大小的單表),常規查詢需要訪問的數據實踐中90%情況下是不會超過20%的,此時建立合理的索引是有效的方法之一
l均衡負載:即應該把任務分時段均衡調度
如一般系統白天是訪問高峯,如果此時備份任務、批處理任務或報表數據抽取任務也 在這個時段則易造成負載峯值現象,正確的做法應該是把備份任務、批處理任務和報表數據抽取任務放到晚上進行處理,或採用並行化策略
l並行化負載:即大數據量的查詢訪問需要使用併發策略
如在數據倉庫環境中應該多使用併發策略,此舉可以明顯減少響應時間
 
 
SQL優化階段
 
 
使用OEM發現頂級SQL
 
 
在OEM中,選擇性能->其它監視鏈接->定級活動,如下圖:
 
 
不要用*代替所有列名
 
 
指定僅僅需要的列名與使用*對比:
時間:359/1327=27.05%  CUP耗費: 4092121327/6413227637=63.81%
IO耗費: 29601/110117=26.88% 可見大幅降低I/O從而降低響應時間!
 
 
SQL優化技巧
使用TRUNCATE代替DELETE
  Oralce執行DELETE後會使用UNDO表空間存放被刪除的信息以便恢復,如果之後用戶使用ROLLBACK而不是COMMIT,則Oralce將利用該UNDO表空間中的數據進行恢復。當使用TRUNCATE時,Oracle不會將刪除的數據放入UNDO表空間,因而速度要快很多。當要刪除某個表中的全部數據時,應該使用TRUNCATE而不是不帶WHERE條件的DELETE。語法如下:
 TRUNCATE TABLE table_name [DROP|REUSE STORAGE]
 DROP STORAGE爲默認的方式,表示收回被刪除的表空間
 REUSER STORAGE表示保留被刪除的空間以供該表的新數據使用
 
 應用開發中,可以編寫一個子程序讓其動態的清除空表,以供調用。
默認PCTFREE爲10,假定爲5,high-water mark是一個存儲段分配多少存儲器的標記。
 
 
 
 
 
 
 
活用COMMIT
  PL/SQL塊中,經常將幾個相互聯繫的DML語句寫在BEGIN …END,如果不影響事務的完整性,則建議在每個END前面寫一個COMMIT,以達到 對DML的及時提交 釋放事務所佔的資源的目的。
  COMMIT釋放的資源包括:
lUNDO段上用於恢復數據的信息
l事物中DML語句獲得的鎖
lSGA中重做日誌緩衝區中的空間
lOracle爲管理相關資源(如上述資源) 而開銷的內部資源
體驗例子流程如下 
體驗例子顯示 
 
減少表的查詢次數
 
1.一個邏輯單元中,將能讀出的列一次性讀出,且儘量存放在本地變量中,應該杜絕不要用一個讀一個
 
2.在包含子查詢的SQL中,要特別注意減少對錶的查詢次數,在代碼清晰時對於能減少查詢次數的應堅決減少,舉例如下:
2.執行計劃如下,結論是什麼? 
 
以EXISTS代替DISTINCT
多表信息的查詢時,避免在SELECT子句中使用DISTINCT. 一般可以考慮用EXISTS替換, EXISTS 使查詢更爲迅速,因爲此時RDBMS核心模塊將在子查詢的條件一旦滿足後,立刻返回結果。
 
優化前:
 
優化後:
 
使用默認值
 
使用默認之後的執行時間比爲1.063/2.657=40.01%,快了一倍多!
可見在不含默認值,是null的列上沒有使用索引,是全表掃描!而使用了默認值的列上使用了索引範圍掃描!
 
l不能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列的情況下,只要這些列中有一列含有null,該列就會從索引中排除。也就是說如果某列存在空值,即使對該列建索引也不會提高性能
l任何在where子句中使用is null或is not null的語句優化器是不允許使用索引的
l如果每列確實可能存在空值的情況,可以使用默認值的方式替代以便充分利用索引提高性能
 
使用DECODE函數減少處理步驟

 
l使用DECODE函數可以避免重複掃描相同記錄或重複連接相同的表.
lDECODE函數也可以運用於GROUP BY 和ORDER BY子句中.
l上述例子有兩步相似的操作,使用DECODE後節省一半時間,如果一組相似的操作越多,節省的時間則越多,計算公式爲n-1,其中n爲相似操作的步驟數
 
通配符的使用技巧
 
上例中已知數據%DX_ACCOUNT_TRADE%,只有以I開頭的
首位使用通配符是首位不使用通配符執行效率的:0.031/1.891=1.639%
 
l當通配符出現在LIKE後面字符串的首位時,索引將不會被使用,因此在已知某字符的情況下,LIKE查詢中應儘量不要把通配符寫在首位
l%代表不定長的字符,_代表定長的字符,如果在確定要通配的字符長度時,應該儘量使用_,而不是%
 
定義並執行嚴格的SQL編寫規範
 
使用Oracle共享遊標的優點是:
l降低和減少Oracle對SQL的解析數量
l動態調整內存
l提高內存的使用率
 
風格請參照前面章節中的“建議的程序風格”
  
表的連接方式 
FROM表順序選擇
  使用基於規則的優化器(CBO)時,Oracle解析器按照從右到左的順序處理FROM子句的表明,即FROM子句中最後的表(驅動表)會最先被處理。
  當FROM子句包含多個表時,建議將記錄最少的表(一般是字典表)放在最後面。當Oracle處理多個表時,一般採用排序或合併的方式連接這些表,系統首先會掃描FROM子句部分的最後一個表,並對該表的數據行進行排序;然後掃描倒數第二個表,並將從該表中取出的記錄與第一個表中的記錄進行匹配合並,依此類推。
如果是大於兩表相關聯,最好選擇交叉表爲驅動表,交叉表是指被其它表所引用的表。
 
 
  
 
 
RBO模式下,小表爲驅動表的執行時間爲大表是驅動的執行時間的:
0.078/2.253 = 2.26%!
 
驅動表的選擇
 
 
此時的優化器模式爲CBO,二者的執行時間僅僅相差:
0.328-0.313=0.015毫秒,二者幾乎接近,這是爲什麼呢?我們再看二者執行計劃:
 
 
我們發現,此時二者的執行計劃 一模一樣!這又是爲什麼?
驅動表的選擇
驅動表(Driving Table)是指被最先訪問的表,通常是以全表掃描的方式訪問的。
    如果優化器是CBO,則優化器會檢查SQL語句中每個表的物理大小、索引狀態,然後尋找開銷最小的執行路徑。如果優化器是RBO,且所有連接條件都有索引對應,則驅動表是FROM子句中最後一個表。
無論如何,我們建議始終將記錄小的表(如字典表)作爲驅動表,則能適應CBO和RBO!
 
WHERE子句如何寫
Oralce優化器的原理是採用自下而上的順序解析WHERE子句,因此表之間的連接必須寫在其他WHERE條件之前, 可過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾 。
 
 
 
上述SQL語句的例子雖然符合優化規範的比不符合優化規範的寫法僅僅快了不到0.4秒,但重要的是這是在當前單機環境、且沒有任何其它數據庫事務、業務很簡單、連接的表僅有兩個表的情況下。如果在實際的大業務量環境下,則這種優化效應將成 倍數級增長!
因此,我們建議任何時候編寫SQL語句時要 使用表的別名 對錶的連接永遠 寫在WHERE後面的第一個位置,並對過濾條件進行估算, 按照降序的大小將這些 條件從WHERE子句最後部分往前排列
 
習題
1.SQL優化的步驟包含那幾步?可以使用那幾種工具或方法發現糟糕的SQL?
2.SQL調節的三大目標是什麼?請舉例來說明如何均衡負載。
3.一般來說,SQL優化包括三個階段,分別是語法分析、優化和執行階段。請問,語法分析階段的主要任務是什麼?Oracle在優化階段優化器主要執行的任務和考慮的因素又分別包含哪些?
4.在SELECT少用*,多用具體的列名其理論依據是什麼?
5.Truncate包含幾種用法?畫圖並解釋Truncate如何改變高水位線。
6.舉例說明什麼情況下應該儘量多用COMMIT,什麼情況下不能。
7.使用DECODE合併多個相類似操作,其與減少對數據庫的查詢次數有關係嗎?
8.應該避免那種不合適的通配符的使用方法?
9.解釋什麼是驅動表,應該如何選擇驅動表。
10.推薦的FROM子句和WHERE子句應該如何寫,並解釋其原理。
 
轉載請註明私塾在線【 http://sishuok.com/forum/blogPost/list/0/6413.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章