某交易查詢庫主要使用Oracle 12.1.0.2.0的In Memory特性緩存三張按月分區的大表,In Memory組件主要是針對OLAP應用的,而這種應用絕大部分的操做都是查詢,並且不少時候只關心表中特定的一個或多個列,因此in memory特性還能夠指定只把表中的特定的一個或多個列加載到in memory area當中。開始的狀況因爲併發等多種因素,跑的仍是很快的。隨着時間的推移,三個表的數據量愈來愈大,所佔用內存資源也愈來愈多。老是出現這樣那樣的問題。現在年上半年該系統的一次故障。算法
SQL> r
1 select wait_class_id,wait_class,count() cnt
2 from dba_hist_active_sess_history
3 where snap_id between 12073 and 12074
4 group by wait_class_id,wait_class
5 order by 3 desc數據庫
WAIT_CLASS_ID WAIT_CLASS CNT緩存
1740759767 User I/O 12472
2363
3386400367 Commit 2301
1893977003 Other 1093
3875070507 Concurrency 132
4217450380 Application 67
4108307767 System I/O 21
3290255840 Configuration 1session
8 rows selected.架構
查詢對應的IO狀況所反應到數據庫中的事件是什麼
EVENT_ID EVENT CNT併發
3056446529 read by other session 6149
834992820 db file parallel read 4756
2652584166 db file sequential read 1418
3926164927 direct path read 993
506183215 db file scattered read 56
根據其等待時間,查看對應的SQL文本爲:oracle
SELECT
FROM (SELECT tmp_page., rownum row_id
FROM (SELECT t.TRAN_UUID,
t.IN_MNO,
t.EX_MNO merchantCode,
t.CARD_TYP,
t.CARD_DISP_NO,
t.TRAN_RESPONSE_CD,
t.TRAN_CD,
t.TRAN_STS,
t.TRAN_SEQ_NO,
t.TRAN_BAT_NO,
to_char(t.TRAN_DATE_TIME, 'YYYYMMDD') AS TRAN_DT,
to_char(t.TRAN_DATE_TIME, 'HH24MISS') AS TRAN_TM,
t.TRAN_IN_MOD payWay,
t.TERMINAL_NUM,
t.POS_SIGN_FLG,
t.TRAN_AMT,
t.RECEIVER_FEE_AMT,
t.TRAN_FLG,
t.ROOT_XXXX_ORG_NM belongtoOrgNm,
t.BUSINESS_EMP_NM empNm,
t.XXXX_ORG_NM directlyOrg,
t.XXXX_ORG_NO,
t.XXXX_ORG_PATH
FROM T_SSP_TRANDATA_MPOS t
WHERE t.TRAN_DATE BETWEEN TO_DATE(:1, 'yyyyMMdd') AND
TO_DATE(:2, 'yyyyMMdd')
AND t.ROOT_XXXX_ORG_NO = :3
AND t.XXXX_ORG_PATH LIKE :4 || '%'
ORDER BY t.TRAN_DATE_TIME DESC) tmp_page
WHERE rownum < = :5)
WHERE row_id > :6;ide
執行計劃相似以下:
優化
使用AWR對比相同時間不一樣日期時間段,查看該SQL在前一天單次執行時間爲1,168毫秒,約0.01分。執行頻率爲171,故障時間段單次執行時間爲102,929毫秒,約1.71分。執行的頻率爲248。故障時間段要比平時多執行77次。多出131.67分。
推測故障時間段明顯比前一天的執行頻率要高。是否存在前臺的用戶點擊某個按鈕,等了半天沒響應,而後就一直點,致使這個SQL一直重複的運行。spa
IO資源幾乎耗盡,會話a在進行把磁盤上的數據塊讀到內存,會話b,會話c 同時也請求這個數據塊。就致使了b、c read by other session。
direct path read表小的時候將數據讀到緩存中,表不斷增大後,oracle算法干預在大於2%的cache後會採用直接路勁讀的方式,跳過加載緩存。大量的反覆讀取磁盤IO會將IO耗盡,決定設定10949事件關閉該特性。
要使用IN MEMORY特性,須要設置parallel_degree_policy=AUTO和parallel_force_local=false,纔可以真正意義上的啓動IM特性,否則只是執行計劃中的啓用,是假象。
後將parallel_degree_policy改成AUTO。後又從新加載T_SSP_TRANDATA_MPOS表所有進入in memory。這麼一折騰後,系統穩定了一段時間,可後期還有這樣那樣的問題。
在代碼不改動的狀況下,開發和架構部同事進行了拆表分庫的方案。三個大表廢棄一張表,另外兩個表拆分紅爲4個表,並按月又進行了拆分,一個月有四個小表。新庫遷移完成,投產當晚,進行數據校驗的同時發現該查詢功能仍是跑不出結果該SQL單次執行時間150S以
上,改造這麼久沒法交差啊。
着手查看SQL,進行SQL優化。
SELECT
FROM (SELECT tmp_page., rownum row_id
FROM (SELECT to_char(TRAN_DATE_TIME, 'yyyyMMdd HH24:mm:ss'),
t.TRAN_UUID,
t.IN_MNO,
t.EX_MNO merchantCode,
t.CARD_TYP,
t.CARD_DISP_NO,
t.TRAN_RESPONSE_CD,
t.TRAN_CD,
t.TRAN_STS,
t.TRAN_SEQ_NO,
t.TRAN_BAT_NO,
to_char(t.TRAN_DATE_TIME, 'YYYYMMDD') AS TRAN_DT,
to_char(t.TRAN_DATE_TIME, 'HH24MISS') AS TRAN_TM,
t.TRAN_IN_MOD payWay,
t.TERMINAL_NUM,
t.POS_SIGN_FLG,
t.TRAN_AMT,
t.RECEIVER_FEE_AMT,
t.TRAN_FLG,
t.XXXX_ORG_NO,
t.XXXX_ORG_PATH
FROM T_TRADE_201807_MPOS_2_0001 t
WHERE t.TRAN_DATE BETWEEN TO_DATE('20180701', 'yyyyMMdd') AND
TO_DATE('20180730', 'yyyyMMdd')
AND t.ROOT_XXXX_ORG_NO = '6AAAAAAAAA'
AND t.XXXX_ORG_PATH LIKE '0FDAFDS%'
ORDER BY t.TRAN_DATE_TIME DESC) tmp_page
WHERE rownum < = 10)
WHERE row_id > 0;
以下是執行計劃:
該表索引狀況:
OWNER INDEX_NAME COLUMN_NAME
XXXX IDX_1807_MPOS_21_XXXX_ORG_NO XXXX_ORG_NO
XXXX IDX_1807_MPOS_21_IN_MNO IN_MNO
XXXX IDX_1807_MPOS_21_ROOT_XXXX_N ROOT_XXXX_ORG_NO
XXXX IDX_1807_MPOS_21_TRAN_DT TRAN_DATE
XXXX IDX_1807_MPOS_21_TRAN_TM TRAN_DATE_TIME
XXXX PK_T_SSP_1807_MPOS_21 TRAN_UUID
XXXX PK_T_SSP_1807_MPOS_21 TRAN_DATE
咱們都知道建立索引須要查看該表的基數狀況,根據基數與總行數的比值咱們就能知道該表某個列的選擇性。
該7月表的總行數18228172條,ROOT_XXXX_ORG_NO列的基數爲1,說明都是重複值該列。
而這個ROOT_XXXX_ORG_NO索引的選擇性過低了。絕對是不推薦建立索引的!當一個表中的列選擇性大於20%的時候,說明該列數據分佈比較均衡。且出如今where條件中,該列沒有建立索引,那麼該列就必須建立索引。
不想多說什麼了,既然開發部門的同事在領導面前沒法交差,咱們試着看看有沒有優化的餘地。
首先收集一下該表的統計信息,以及作一下動態採樣。執行時間縮短很多。
明確一下分頁語句必定排序,要否則每次返回結果都不同。業務邏輯不嚴謹的話還行。
這裏須要看where條件後面的字段了。
當where條件是等值,oder by其餘列,那麼where條件的列在前,其餘列在後。
當where條件不等值,order by其餘列,那麼建立索引就不必定怎麼建了,關鍵看過濾的數據多很少!!!
基於以上考慮狀況,建立以下索引:
create index xxx.IDX_1807_MPOS_21_NO_PA on xxx.T_TRADE_201807_MPOS_2_0001 ("TRAN_DATE_TIME","ROOT_xxxx_ORG_NO","xxxx_ORG_PATH") tablespace XXX_IDX online nologging;
結果秒出,開發部門的同事能夠交差了。
經過咱們的監控系統也能感覺到這次的優化狀況,如CPU利用率
內存使用率
DBtime監控
由原來的各類突起峯值,到如今的平穩運行。
這裏有幾個疑問,這樣的索引跳掃是否有問題?返回的行數爲何不是10行?歡迎你們積極討論。
總得留點懸念吧