利用複合索引解決效能問題一例

來源:互聯網
上載者:User
利用複合索引解決效能問題一例

轉帖自: http://www.laoxiong.net/composite_index_overcome_performance_problem.html

 

老熊的部落格(http://www.laoxiong.net)

 

Oracle效能最佳化 12月 8th, 2008

故障發生時間:12月6日早上
系統內容:HP Superdome系列,128G記憶體,64CPU,Oracle 9.2.0.8
故障現象:CPU佔用將近100%,運行隊列達到60-80,應用反應速度很慢。

這是一個省級電信的核心系統。

在使用者反映速度很慢後,在主機上檢查發現CPU很高,將近100%,而運行隊列達到了60-80。檢查Oracle,發現很多的會話在等待latch free,latch#為98

SQL> select * from v$latchname where latch#=98;

    LATCH# NAME
---------- ----------------------------------------------------------------
        98 cache buffers chains

檢查正在等待latch free的會話正在執行的SQL,大部分都在執行類似於下面的SQL:

SELECT SUM(cnt),
       to_char(nvl(SUM(nvl(amount, 0)) / 100, 0), ’FM9999999999990.90′) amount
  FROM (select count(payment_id) cnt, SUM(amount) amount
          from payment
         where staff_id = 592965
           and CREATED_DATE >= trunc(sysdate)
           and state = ’C0C’
           and operation_type in (’5KA’, ’5KB’, ’5KC’, ’5KP’))

看起來這個SQL並不複雜,查看其執行計畫:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             |  Name                      | Rows  | Bytes | Cost  | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                            |     1 |    26 |   125K|       |       |
|   1 |  SORT AGGREGATE                       |                            |     1 |    26 |       |       |       |
|   2 |   VIEW                                |                            |     1 |    26 |   125K|       |       |
|   3 |    SORT AGGREGATE                     |                            |     1 |    30 |       |       |       |
|*  4 |     TABLE ACCESS BY GLOBAL INDEX ROWID| PAYMENT                    | 19675 |   576K|   125K| ROWID | ROW L |
|*  5 |      INDEX RANGE SCAN                 | IDX_PAYMENT_CREATED_DATE8  |  1062K|       |  3919 |       |       |
--------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter(”PAYMENT”.”STAFF_ID”=521840 AND ”PAYMENT”.”STATE”=’C0C’ AND (”PAYMENT”.”OPERATION_TYPE”=’5KA’ OR
              ”PAYMENT”.”OPERATION_TYPE”=’5KB’ OR ”PAYMENT”.”OPERATION_TYPE”=’5KC’ OR ”PAYMENT”.”OPERATION_TYPE”=’5KP’))
   5 - access(”PAYMENT”.”CREATED_DATE”>=TRUNC(SYSDATE@!))

Note: cpu costing is off

從執行計畫裡面可以看到,Oracle評估出,利用索引掃描返回的行數高達100萬行,可想而知,這就是產生眾多latch buffers chains latch爭用的原因。
檢查PAYMENT表的索引:

SQL> select index_name,index_type from dba_indexes where table_name=’PAYMENT’ and table_owner=’ACCT’;

INDEX_NAME                     INDEX_TYPE
------------------------------ ---------------------------
IDX_OPERATED_PAYMENT_SERIAL8   NORMAL
IDX_PAYMENT_ACCT_ID8           NORMAL
IDX_PAYMENT_CREATED_DATE8      NORMAL
IDX_PAYMENT_PAYED_METHOD8      NORMAL
IDX_PAYMENT_PAYMENT_METHOD8    NORMAL
IDX_PAYMENT_SERV_ID8           NORMAL
IDX_PAYMENT_STAFF_DATE8        NORMAL
IDX_PAYMENT_STATE_DATE8        NORMAL
PK_PAYMENT13                   NORMAL

SQL> select index_name,column_name,column_position from
dba_ind_columns where table_owner=’ACCT’ and table_name=’PAYMENT’ order
by 1,3;

INDEX_NAME                     COLUMN_NAME                    COLUMN_POSITION
------------------------------ ------------------------------ ---------------
IDX_OPERATED_PAYMENT_SERIAL8   OPERATED_PAYMENT_SERIAL_NBR                  1
IDX_PAYMENT_ACCT_ID8           ACCT_ID                                      1
IDX_PAYMENT_CREATED_DATE8      CREATED_DATE                                 1
IDX_PAYMENT_PAYED_METHOD8      PAYED_METHOD                                 1
IDX_PAYMENT_PAYMENT_METHOD8    PAYMENT_METHOD                               1
IDX_PAYMENT_SERV_ID8           SERV_ID                                      1
IDX_PAYMENT_STAFF_DATE8        STAFF_ID                                     1
IDX_PAYMENT_STAFF_DATE8        STATE_DATE                                   2
PK_PAYMENT13                   PAYMENT_ID                                   1

可以看到執行計畫中的使用的索引IDX_PAYMENT_CREATED_DATE8是在CREATED_DATE列上建立的單列索引。

這個SQL在之前卻沒有出現這個問題,那問題在哪裡?
如果瞭解電信系統的人,會知道在出帳後會有一個批量銷帳的動作,這導致在這個特殊的時間裡,用
CREATED_DATE>=TRUNCATE(SYSDATE)這個條件會從索引掃描中返回大量的行。而實際上而回表之後用其他條件過濾後的行數
僅約2萬行(這是評估的資料,實際的資料遠遠比這個少)。很顯然,如果我們建立一個複合索引,那麼索引掃描返回的行數將大大減少。這裡STAFF_ID這
個欄位是與CREATED_DATE建立複合索引最好的欄位。

在STAFF_ID和CREATE_DATE列上建立複合索引後,系統馬上恢複正常。不過這裡把STAFF_ID做為複合索引的前置列,有兩個方面
的考慮,一個是根據這個SQL來看,這會大大減少索引葉塊的邏輯讀數量;二是會減少索引葉塊的熱點競爭(CREATE_DATE是單向增長的欄位)。至於
深層次的分析,則要結合應用,必竟做為故障處理,首要的目標是解決當前的問題。

總結:
利用合適的複合索引,能夠有效地減少索引掃描返回的行數,提高效能
熟悉應用系統的業務,可以更清楚地知道問題的根源,減少故障處理時間

 

 

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

老熊水平高,許多基礎知識沒說。現整理一下老熊解決問題的基本流程:

1.會話的等待事件可以通過v$session_wait來尋找,然後通過v$session和v$sql即可找到相對應的sql語句,樣本:

select<br /> u.sid,<br /> substr(u.username,1,12) user_name,<br /> s.sql_text<br />from<br /> v$sql s,<br /> v$session u<br />where<br /> s.hash_value = u.sql_hash_value<br />and<br /> sql_text not like '%from v$sql s, v$session u%'<br />order by<br /> u.sid;

 剩下的老熊就講的蠻仔細的了。

向老熊致敬!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.