1. 程式人生 > 其它 >百倍效能的PL/SQL優化案例(r11筆記第13天)

百倍效能的PL/SQL優化案例(r11筆記第13天)

優化的方式:

一、SQL語句的優化

1、表儘量使用別名,欄位儘量使用別名.欄位名,這樣子,可以減少oracle資料庫解析欄位名。而且把不需要的欄位名剔除掉,只保留有用的欄位名,不要一直使用 select *。

2、關聯查詢時,選擇好主表。oracle解析器對from 後面的表的解析是從右到左的,所以把資料量較小的表作為主表,然後和其他表進行關聯,假如存在三個以下表,把同時交叉關聯的表作為主表,提高查詢效率。

3、where 條件後面的的條件解析是從下向上,從後先前解析執行的,所以可以把過濾資料量較多的條件放在最後面。

4、多利用表中資料行的rowid,rowid代表著表中資料存在的實體地址。例如刪除重複記錄的時候,可以根據rowid進行刪除。

5、減少對錶的查詢,特別在子查詢中,能儘量少重複訪問表,就減少。

6、避免使用耗資源的操作,如distinct、Union、minus等這種需要全表查詢的操作。

7、優化分組group by ,對group by欄位要進行新增鎖引,如果分組當中含有查詢條件,要改寫為where條件進行過濾後,再進行分組,而不是直接進行 having 條件。

8、用EXISTS替代IN、用NOT EXISTS替代 NOT IN,因為 not in是低效的,它必須對該欄位的全部資料進行排序。

9、要合理利用索引欄位提高查詢效率。特別是常用的關聯欄位可以增加索引,主鍵、或者某些唯一欄位。

10、利用>=替代>,因為>=可以直接定位到=的位置,而大於必須先定位位置,然後再查詢下一個資料。耗時不一樣。

11、最後一個一定要學會檢視執行計劃,檢視相關查詢條件是否進入索引,找出問題所在,定位問題。

二、通過索引優化

  索引建立準則:

  1. 確定針對該表的操作是⼤量的查詢操作還是⼤量的增刪改操作。
  2. 嘗試建⽴索引來幫助特定的查詢。檢查⾃⼰的sql語句,為那些頻繁在where⼦句中出現的欄位建⽴索引。
  3. where語句中不得不對查詢列採⽤函式查詢,如upper函式,最好建⽴相應函式索引;
  4. 在SQL語句中經常進⾏GROUP BY、ORDER BY的欄位上建⽴索引
  5. ⽤於聯接的列(主健/外健)上建⽴索引;
  6. 在經常存取的多個列上建⽴複合索引,但要注意複合索引的建⽴順序要按照使⽤的頻度來確定;
  7. 嘗試建⽴複合索引來進⼀步提⾼系統性能。修改複合索引將消耗更長時間,同時,複合索引也佔磁碟空間。
  8. 對於⼩型的表,建⽴索引可能會影響效能
  9. 在不同值較少的欄位上不必要建⽴索引,如性別欄位;
  10. 應該避免對具有較少值的欄位進⾏索引。
  11. 避免選擇⼤型資料型別的列作為索引。
  12. 預設情況下建⽴的是⾮簇集索引,但在以下情況下最好考慮簇集索引,如:含有有限數⽬(不是很少)唯⼀的列;進⾏⼤範圍的查詢;
  13. 充分的利⽤索引可以減少表掃描I/0的次數,有效的避免對整表的搜尋。當然合理的索引要建⽴在對各種查詢的分析和預測中
  14. 避免在有⼤量併發DML運算的表中使⽤Bitmap索引;
  15. 經常被更新,或者⼀個表雖然很⼤,但是如果多數查詢返回結果都超過表中總⾏數的4%,那麼⼀般認為也是不宜建⽴索引的。
  16. 經常查詢的記錄數⽬少於表中所有記錄總數的5%時就應當建立索引
  17. 儲存索引的表空間最好單獨設定
  18. 隨著資料的變化,索引的效率會下降,因此應定期重建索

三、通過分割槽優化

當表中的資料量不斷增⼤,查詢資料的速度就會變慢,應⽤程式的效能就會下降,這時就應該考慮對錶進⾏分割槽。表進⾏分割槽後,邏輯上表仍然是⼀張完整的表,只是將表中的資料在物理上存放到多個表空間(物理⽂件上),這樣查詢資料時,不⾄於每次都掃描整張表。

Oracle中提供了以下⼏種表分割槽:
⼀、範圍分割槽:這種型別的分割槽是使⽤列的⼀組值,通常將該列成為分割槽鍵。

⼆、列表分割槽:該分割槽的特點是某列的值只有⼏個,基於這樣的特點我們可以採⽤列表分割槽。

三、雜湊(雜湊)分割槽:這類分割槽是在列值上使⽤雜湊演算法,以確定將⾏放⼊哪個分割槽中。當列的值沒有合適的條件時,建議使⽤雜湊分割槽。

四、複合範圍列表分割槽:這種分割槽是基於範圍分割槽和列表

四、通過優化器hint 優化

Hint的具體⽤法
和優化器相關的hint
1/*+ ALL_ROWS */
表明對語句塊選擇基於開銷的優化⽅法,並獲得最佳吞吐量,使資源消耗最⼩化.
SELECT /*+ ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 
2/*+ FIRST_ROWS(n) */
表明對語句塊選擇基於開銷的優化⽅法,並獲得最佳響應時間,使資源消耗最⼩化.
SELECT /*+FIRST_ROWS(20) */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 
3/*+ RULE*/
表明對語句塊選擇基於規則的優化⽅法.
SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 
和訪問路徑相關的hint
1/*+ FULL(TABLE)*/
表明對錶選擇全域性掃描的⽅法.
SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT'; 
2/*+ INDEX(TABLE INDEX_NAME) */
表明對錶選擇索引的掃描⽅法.
SELECT /*+INDEX(BSEMPMS SEX_INDEX) */ * FROM BSEMPMS WHERE SEX='M'; 
5/*+ INDEX_ASC(TABLE INDEX_NAME)*/
表明對錶選擇索引升序的掃描⽅法.
SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ * FROM BSEMPMS WHERE DPT_NO='SCOTT'; 
6/*+ INDEX_COMBINE*/
為指定表選擇點陣圖訪問路經,如果INDEX_COMBINE中沒有提供作為引數的索引,將選擇出點陣圖索引的布林組合⽅式.
SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI) */  * FROM BSEMPMS
WHERE SAL<5000000 AND HIREDATE 
7/*+ INDEX_JOIN(TABLE INDEX_NAME1 INDEX_NAME2) */
當謂詞中引⽤的列都有索引的時候,可以通過指定採⽤索引關聯的⽅式,來訪問資料
select /*+ index_join(t t_ind t_bm) */ id from t where id=100 and object_name='EMPLOYEES' 
8/*+ INDEX_DESC(TABLE INDEX_NAME)*/
表明對錶選擇索引降序的掃描⽅法.
SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ * FROM BSEMPMS WHERE DPT_NO='SCOTT'; 
9/*+ INDEX_FFS(TABLE INDEX_NAME) */
對指定的表執⾏快速全索引掃描,⽽不是全表掃描的辦法.
SELECT /* + INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';
10/*+ INDEX_SS(T T_IND) */
從9i開始,oracle引⼊了這種索引訪問⽅式。當在⼀個聯合索引中,某些謂詞條件並不在聯合索引的第⼀列時,可以通過Index Skip Scan來
訪問索引獲得資料。當聯合索引第⼀列的唯⼀值個數很少時,使⽤這種⽅式⽐全表掃描效率⾼。
和表的關聯相關的hint
/*+ leading(table_1,table_2) */
在多表關聯查詢中,指定哪個表作為驅動表,即告訴優化器⾸先要訪問哪個表上的資料。
select /*+ leading(t,t1) */ t.* from t,t1 where t.id=t1.id; 
/*+ order */
讓Oracle根據from後⾯表的順序來選擇驅動表,oracle建議使⽤leading,他更為靈活
select /*+ order */ t.* from t,t1 where t.id=t1.id;
/*+ use_nl(table_1,table_2) */ 
在多表關聯查詢中,指定使⽤nest loops⽅式進⾏多表關聯。
select /*+ use_nl(t,t1) */ t.* from t,t1 where t.id=t1.id;
/*+ use_hash(table_1,table_2) */ 
在多表關聯查詢中,指定使⽤hash join⽅式進⾏多表關聯。
select /*+ use_hash(t,t1) */ t.* from t,t1 where t.id=t1.id;
在多表關聯查詢中,指定使⽤hash join⽅式進⾏多表關聯,並指定表t為驅動表。
select /*+ use_hash(t,t1) leading(t,t1) */ t.* from t,t1 where t.id=t1.id;
/*+ use_merge(table_1,table_2) */ 
在多表關聯查詢中,指定使⽤merge join⽅式進⾏多表關聯。
select /*+ use_merge(t,t1) */ t.* from t,t1 where t.id=t1.id;
/*+ no_use_nl(table_1,table_2) */ 
在多表關聯查詢中,指定不使⽤nest loops⽅式進⾏多表關聯。
select /*+ no_use_nl(t,t1) */ t.* from t,t1 where t.id=t1.id;
/*+ no_use_hash(table_1,table_2) */ 
在多表關聯查詢中,指定不使⽤hash join⽅式進⾏多表關聯。
select /*+ no_use_hash(t,t1) */ t.* from t,t1 where t.id=t1.id;
/*+ no_use_merge(table_1,table_2) */ 
在多表關聯查詢中,指定不使⽤merge join⽅式進⾏多表關聯。
select /*+ no_use_merge(t,t1) */ t.* from t,t1 where t.id=t1.id;
其他常⽤的hint
/*+ parallel(table_name n) */ 
在sql中指定執⾏的並⾏度,這個值將會覆蓋⾃⾝的並⾏度
select /*+ parallel(t 4) */ count(*)  from t;
/*+ no_parallel(table_name) */ 
在sql中指定執⾏的不使⽤並⾏
select /*+ no_parallel(t) */ count(*)  from t;
/*+ append */以直接載入的⽅式將資料載入⼊庫
insert into t /*+ append */ select * from t;
/*+ dynamic_sampling(table_name n) */
設定sql執⾏時動態採⽤的級別,這個級別為0~10
select /*+ dynamic_sampling(t 4) */ * from t where id > 1234 
/*+ cache(table_name) */ 
進⾏全表掃描時將table置於LRU列表的最活躍端,類似於table的cache屬性
select /*+ full(employees) cache(employees) */ last_name from employees

 

詳細檢視:https://www.csdn.net/tags/MtTaIgysOTI4NzItYmxvZwO0O0OO0O0O.html --MySQL/Oracle資料庫優化總結(非常全面)

     https://blog.csdn.net/ctypyb2002/article/details/102712900  --oracle 常用的 hints

     https://www.cnblogs.com/laiyaling/p/12803873.html?ivk_sa=1024320u --oracle效能優化之索引