oracle的SQL語句效能優化

2021-07-30 16:32:52 字數 3185 閱讀 6692

使用oracle資料庫的應用系統,有時出現sql效能突然變差,特別是對於oltp型別系統執行頻繁的核心sql,如果出現效能問題,通常會影響整個資料庫的效能,進而影響整個系統的正常執行。

這是常常遇到的問題,也是一些dba的挑戰。

sql效能變差原因分析

sql的效能變差,通常是在sql語句重新進行了解析,解析時使用了錯誤的執行計畫出現的。

下列情況是sql會重新解析的原因:

sql語句沒有使用繫結變數,這樣sql每次執行都要解析。

sql長時間沒有執行,被刷出shared pool,再次執行時需要重新解析。

在sql引用的物件(表、檢視等)上執行了ddl操作,甚至是結構發生了變化,比如建了乙個索引。

對sql引用的物件進行了許可權更改。

重新分析(收集統計資訊)了sql引用的表和索引,或者表和索引統計資訊被刪除。

修改了與效能相關的部分引數。

重新整理了共享池。

當然重啟資料庫也會使所有sql全部重新解析。

sql重新解析後,跟以前相比,效能突然變差,通常是下列原因:

1. 表和索引的優化統計資訊被刪除,或者重新收集後統計資訊不準確。重新收集統計資訊通常是由於收集策略(方法)不正確引起。比如對分割槽表使用analyze命令而不是用dbms_stats包、收集統計資訊時取樣比例過小等等。oracle優化器嚴重依賴於統計資訊,如果統計資訊有問題,則很容易導致sql不能使用正確的執行計畫。

2. sql繫結變數窺探(bind peeking),同時繫結變數對應的列上有直方圖;或者繫結變數的值變化範圍過大、分割槽資料分布極不均勻:

1) 繫結變數的列上有直方圖:

假如表orders儲存所有的訂單,state列有3種不同的值:0表示未處理,1表示處理成功完成,2表示處理失敗。state列上有乙個索引,表中絕大部分資料的state列為1,0和2佔少數。有下面的sql:

select * from orders where state=:b1

這裡:b1是變數,在大多數情況下這個值為0,則應該使用索引,但是如果sql被重新解析,而第一次執行時應用傳給變數b1值為1,則不會使用索引,採用全表掃瞄的方式來訪問表。對於繫結變數的sql,只在第一次執行時才會進行繫結變數窺探,並以此確定執行計畫,該sql後續執行時全部按這個執行計畫。這樣在後續執行時,b1變數傳入的值為0的時候,仍然是第一次執行時產生的執行計畫,即使用的是全表掃瞄,這樣會導致效能很差。

2) 繫結變數的值變化範圍過大

:同樣假如orders表有一列created_date表示一筆訂單的下單時間,orders表裡面儲存了最近1年的資料,有如下的sql:

select * from orders where created_date >=:b1;

假如大多數情況下,應用傳入的b1變數值為最近幾天內的日期值,那麼sql使用的是created_date列上的索引,而如果b1變數值為5個月之前的乙個值,那麼就會使用全表掃瞄。與上面描述的直方圖引起的問題一樣,如果sql第1次執行時傳入的變數值引起的是全表掃瞄,那麼將該sql後續執行時都使用了全表掃瞄,從而影響了效能。

3) 分割槽資料量不均勻:

對於範圍和列表分割槽,可能存在各個分割槽之間資料量極不均勻的情況下。比如分割槽表orders按地區area進行了分割槽,p1分割槽只有幾千行,而p2分割槽有200萬行資料。同時假如有一列product_id,其上有乙個本地分割槽索引,有如下的sql:

select * from orders where area=:b1 and produce_id=:b2;

這條sql由於有area條件,因此會使用分割槽排除。如果第1 次執行時應用傳給b1變數的值正好落在p1分割槽上,很可能導致sql採用全表掃瞄訪問,如前面所描述的,導致sql後續執行時全部使用了全表掃瞄。

3. 其他原因,比如表做了類似於move操作之後,索引不可用,對索引進行了更改。當然這種情況是屬於維護不當引起的問題,不在本文討論的範圍。

綜上所述,sql語句效能突然變差,主要是因為繫結變數和統計資訊的原因。注意這裡只討論了突然變差的情況,而對於由於資料量和業務量的增加效能逐步變差的情況不討論。

如何保持sql效能的穩定

為保持sql效能或者說是執行計畫的穩定性,需要從以下幾個方面著手:

1. 規劃好優化統計資訊的收集策略。

對於oracle 10g來說,預設的策略能夠滿足大部分需求,但是預設的收集策略會過多地收集列上的直方圖。由於繫結變數與直方圖固有的矛盾,為保持效能穩定,對使用繫結變數的列,不收集列上的直方圖;對的確需要收集直方圖的列,在sql中該列上的條件就不要用繫結變數。

統計資訊收集策略,可以考慮對大部分表,使用系統預設的收集策略,而對於有問題的,可以用dbms_stats.lock_stats鎖定表的統計資訊,避免系統自動收集該錶的統計資訊,然後編寫指令碼來定製地收集表的統計資訊。指令碼中類似如下:

2. 修改sql語句,使用hint,使sql語句按hint指定的執行計畫進行執行。

這需要修改應用,同時需要逐條sql語句進行,加上測試和發布,時間較長,成本較高,風險也較大。

3. 修改隱含引數」 _optim_peek_user_binds」為false

,修改這個引數可能會引起效能問題(這裡討論的是穩定性問題)。

4. 使用outline。

對於曾經出現過執行計畫突然變差的sql語句,可以使用outline來加固其執行計畫。在10g中dbms_outln.create_outline可以根據已有的執行正常的sql游標來建立outline。如果事先對所有頻繁執行的核心sql使用outline加固執行計畫,將最大可能地避免sql語句效能突然變差。

注:dbms_outln可以通過$oracle_home/rdbms/admin/dbmsol.sql指令碼來安裝。

5. 使用sql profile。

sql profile是oracle 10g之後的新功能,此處不再介紹,請參考相應的文件。

除此之外,可以調整一些引數避免潛在的問題,比如將"_btree_bitmap_plans"引數設定為false(這個引數請參考網際網路上的文章或oracle文件)。

而在實際工作中,通過使用定製的統計資訊收集策略,以及在部分系統上使用outline,系統基本上不會出現已有的sql效能突然變差的情況。當然也有維護人員操作不當引起的sql效能突然變差,比如建了某個索引而沒有收集統計資訊,導致sql使用了新建的索引,而該索引並不適合於那條sql;維護人員意外刪除了表個索引的統計資訊。

SQL 語句效能調優

經常聽到有做應用的朋友抱怨資料庫的效能問題,比如非常低的併發,令人崩潰的響應時間,長時間的鎖等待,鎖公升級 甚至是死鎖,等等。在解決這些問題的過程中,dba 經常發現應用開發人員對資料庫的 誤用 包括 返回過多不必要的資料 不必要和不適當加鎖,對隔離級別的誤用和對儲存過程的誤用等等。但是,面對浩如煙...

SQL語句優化效能調優

在語句很規範的情況下,就是加索引。然後最大的收穫就是使用執行計畫 解釋計畫?explain plan windows 這個工具覺得很厲害。可以檢視索引是否使用如下圖 網上查到的sql語句優化大多數都是為了避免全表查詢,在語句不規範的情況下就算加了索引呢也會全表查詢,所以優化就是避免這種情況的發生 還...

Oracle效能調優常用語句

oracle效能調優常用語句 識別 低效執行 的sql語句 select executions disk reads,buffer gets,round buffer gets disk reads buffer gets,2 hit radio,round disk reads execution...