日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

一个通过添加本地分区索引提高SQL性能的案例

發布時間:2024/1/8 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一个通过添加本地分区索引提高SQL性能的案例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天接到同事求助,說有一個select query,在Oracle上要跑一分多鐘,他希望能在5s內出結果,該sql如下:

[sql]? view plain copy print ?
  • Select??/*+?parallel(src,?8)?*/?distinct??
  • ??src.systemname?as?systemname??
  • ??,??src.databasename?as?databasename??
  • ??,??src.tablename?as?tablename??
  • ??,??src.username?as?username??
  • from??<strong>meta_dbql_table_usage_exp_hst</strong>?src??
  • ?inner?<strong>join?DR_QRY_LOG_EXP_HST</strong>?rl?on??
  • ??<strong>src.acctstringdate?=?rl.acctstringdate??
  • ??and?src.queryid?=?rl.queryid</strong>??
  • ??And?Src.Systemname?=?Rl.Systemname??
  • ??and?src.acctstringdate?>?sysdate?-?30??
  • ??And?Rl.Acctstringdate?>?Sysdate?-?30??
  • ?inner?join??<strong>meta_dr_qry_log_tgt_all_hst?</strong>tgt?on??
  • ??upper(tgt.systemname)?=?upper('MOZART')??
  • ??And?Upper(tgt.Databasename)?=?Upper('GDW_TABLES')??
  • ??And?Upper(tgt.Tablename)?=?Upper('SSA_SLNG_LSTG_MTRC_SD')??
  • ??<strong>AND?src.acctstringdate?=?tgt.acctstringdate??
  • ??and?rl.statement_id?=?tgt.statement_id</strong>??
  • ??and?rl.systemname?=?tgt.systemname??
  • ??And?Tgt.Acctstringdate?>?Sysdate?-?30??
  • ??And?Not(??
  • ????Upper(Tgt.Systemname)=Upper(src.systemname)??
  • ????And??
  • ????Upper(Tgt.Databasename)?=?Upper(Src.Databasename)??
  • ????And??
  • ????Upper(Tgt.Tablename)?=?Upper(Src.Tablename)??
  • ????)??
  • ??And???tgt.Systemname?is?not?null??
  • ??And???tgt.Databasename?Is?Not?Null??
  • ??And???tgt.tablename?is?not?null??
  • ;??

  • SQL的簡單分析

    總得來看,這個SQL就是三個表(meta_dbql_table_usage_exp_hst,DR_QRY_LOG_EXP_HST,meta_dr_qry_log_tgt_all_hst)的INNER JOIN,這三個表數據量都在百萬級別,且都是分區表(以acctstringdate為分區鍵),執行計劃如下: [sql]? view plain copy print ?
  • ------------------------------------------------------------------------------------------------------------------------??
  • |?Id??|?Operation??????????????????????????????|?Name??????????????????????????|?Rows??|?Bytes?|?Cost??|?Pstart|?Pstop?|??
  • ------------------------------------------------------------------------------------------------------------------------??
  • |???0?|?SELECT?STATEMENT???????????????????????|???????????????????????????????|?????1?|???159?|??8654?|???????|???????|??
  • |???1?|??PX?COORDINATOR????????????????????????|???????????????????????????????|???????|???????|???????|???????|???????|??
  • |???2?|???PX?SEND?QC?(RANDOM)??????????????????|?:TQ10002??????????????????????|?????1?|???159?|??8654?|???????|???????|??
  • |???3?|????SORT?UNIQUE?????????????????????????|???????????????????????????????|?????1?|???159?|??8654?|???????|???????|??
  • |???4?|?????PX?RECEIVE?????????????????????????|???????????????????????????????|?????1?|????36?|?????3?|???????|???????|??
  • |???5?|??????PX?SEND?HASH??????????????????????|?:TQ10001??????????????????????|?????1?|????36?|?????3?|???????|???????|??
  • |*??6?|???????TABLE?ACCESS?BY?LOCAL?INDEX?ROWID|?DR_QRY_LOG_EXP_HST????????????|?????1?|????36?|?????3?|???????|???????|??
  • |???7?|????????NESTED?LOOPS????????????????????|???????????????????????????????|?????1?|???159?|??8633?|???????|???????|??
  • |???8?|?????????NESTED?LOOPS???????????????????|???????????????????????????????|??8959?|??1076K|??4900?|???????|???????|??
  • |???9?|??????????BUFFER?SORT???????????????????|???????????????????????????????|???????|???????|???????|???????|???????|??
  • |??10?|???????????PX?RECEIVE???????????????????|???????????????????????????????|???????|???????|???????|???????|???????|??
  • |??11?|????????????PX?SEND?BROADCAST???????????|?:TQ10000??????????????????????|???????|???????|???????|???????|???????|??
  • |??12?|?????????????PARTITION?RANGE?ITERATOR???|???????????????????????????????|?????1?|????56?|??4746?|???KEY?|????14?|??
  • |*?13?|??????????????TABLE?ACCESS?FULL?????????|?META_DR_QRY_LOG_TGT_ALL_HST???|?????1?|????56?|??4746?|???KEY?|????14?|??
  • |??14?|??????????PX?BLOCK?ITERATOR?????????????|???????????????????????????????|??8959?|???586K|???154?|???KEY?|???KEY?|??
  • |*?15?|???????????TABLE?ACCESS?FULL????????????|?META_DBQL_TABLE_USAGE_EXP_HST?|??8959?|???586K|???154?|???KEY?|???KEY?|??
  • |??16?|?????????PARTITION?RANGE?ITERATOR???????|???????????????????????????????|?????1?|???????|?????2?|???KEY?|???KEY?|??
  • |*?17?|??????????INDEX?RANGE?SCAN??????????????|?DR_QRY_LOG_EXP_HST_IDX????????|?????1?|???????|?????2?|???KEY?|???KEY?|??
  • ------------------------------------------------------------------------------------------------------------------------??
  • Predicate?Information?(identified?by?operation?id):??
  • ---------------------------------------------------??
  • ??
  • ???6?-?filter("RL"."STATEMENT_ID"="TGT"."STATEMENT_ID"?AND?"RL"."SYSTEMNAME"="TGT"."SYSTEMNAME"?AND?"SRC"."SYSTEMNAME"="RL"."SYSTEMNAME")??
  • ??13?-?filter(UPPER("TGT"."SYSTEMNAME")='MOZART'?AND?UPPER("TGT"."DATABASENAME")='GDW_TABLES'?AND??
  • ??????????????UPPER("TGT"."TABLENAME")='SSA_SLNG_LSTG_MTRC_SD'?AND?"TGT"."ACCTSTRINGDATE">SYSDATE@!-30?AND?"TGT"."SYSTEMNAME"?IS?NOT?NULL??
  • ??????????????"TGT"."DATABASENAME"?IS?NOT?NULL?AND?"TGT"."TABLENAME"?IS?NOT?NULL)??
  • ??15?-?filter("SRC"."ACCTSTRINGDATE"="TGT"."ACCTSTRINGDATE"?AND?(UPPER("TGT"."SYSTEMNAME")<>UPPER("SRC"."SYSTEMNAME")?OR??
  • ??????????????UPPER("TGT"."DATABASENAME")<>UPPER("SRC"."DATABASENAME")?OR?UPPER("TGT"."TABLENAME")<>UPPER("SRC"."TABLENAME"))?AND??
  • ??????????????"SRC"."ACCTSTRINGDATE">SYSDATE@!-30)??
  • ??17?-?access("SRC"."QUERYID"="RL"."QUERYID"?AND?"SRC"."ACCTSTRINGDATE"="RL"."ACCTSTRINGDATE")??
  • ???????filter("RL"."ACCTSTRINGDATE">SYSDATE@!-30)??

  • 定位問題

    從上面執行計劃中的表連接方式可以知道,這三個表之間進行了兩次NESTED LOOP,問題出現在最里層的NESTED LOOP(對兩個表都做了TABLE FULL SCAN),因為表都是百萬級別的(即時過濾后的數據量也不小),性能問題就出現在內表(即被驅動表)META_DBQL_TABLE_USAGE_EXP_HST做了太多次的全表掃描。如果能把全表掃描轉換成索引,則性能可以大幅度提高。
    下面是NESTED LOOP的介紹: 嵌套連接把要處理的數據集分為外部循環(驅動數據源)和內部循環(被驅動數據源),外部循環只執行一次,內部循環執行的次數等于外部循環執行返回的數據個數。
    這種連接的好處是內存使用非常少。
    如果驅動數據源有限,且被驅動表在連接列上有相應的索引,則這種連接方式才是高效的。


    下面是這三個表上索引的情況: [sql]? view plain copy print ?
  • SQL>?select?index_name,?table_name?from?user_indexes?where?table_name?in?('DR_QRY_LOG_EXP_HST',upper('meta_dbql_table_usage_exp_hst'),?upper('meta_dr_qry_log_tgt_all_hs??
  • ??
  • INDEX_NAME???????????????????????????????????????????????????TABLE_NAME??
  • ------------------------------------------------------------?------------------------------------------------------------??
  • META_DR_QRY_LOG_TGT_ALL_IDX??????????????????????????????????META_DR_QRY_LOG_TGT_ALL_HST??
  • META_DBQL_TUSAGE_EHST_IDX????????????????????????????????????META_DBQL_TABLE_USAGE_EXP_HST??
  • DR_QRY_LOG_EXP_HST_IDX???????????????????????????????????????DR_QRY_LOG_EXP_HST??
  • ??
  • CREATE?INDEX?"GV"."META_DR_QRY_LOG_TGT_ALL_IDX"?ON?"GV"."META_DR_QRY_LOG_TGT_ALL_HST"?("STATEMENT_ID",?"ACCTSTRINGDATE")??
  • CREATE?INDEX?"GV"."META_DBQL_TUSAGE_EHST_IDX"?ON?"GV"."META_DBQL_TABLE_USAGE_EXP_HST"?("QUERYID",?"ACCTSTRINGDATE")??
  • CREATE?INDEX?"GV"."DR_QRY_LOG_EXP_HST_IDX"?ON?"GV"."DR_QRY_LOG_EXP_HST"?("QUERYID",?"ACCTSTRINGDATE")??

  • 這三個索引都是本地分區索引(都包含分區鍵acctstringdate),很顯然,DR_QRY_LOG_EXP_HST表少了個索引,因為它與表meta_dr_qry_log_tgt_all_hst 在statement_id上做join,因此應該在它的statement_id上也創建本地分區索引如下: [sql]? view plain copy print ?
  • create?index?DR_QRY_LOG_EXP_HST_IDX2?on?gv.DR_QRY_LOG_EXP_HST?(statement_id,ACCTSTRINGDATE)?local;??

  • 性能對比

    新的執行計劃如下: [sql]? view plain copy print ?
  • ------------------------------------------------------------------------------------------------------------------------??
  • |?Id??|?Operation??????????????????????????????|?Name??????????????????????????|?Rows??|?Bytes?|?Cost??|?Pstart|?Pstop?|??
  • ------------------------------------------------------------------------------------------------------------------------??
  • |???0?|?SELECT?STATEMENT???????????????????????|???????????????????????????????|?????1?|???159?|??4838?|???????|???????|??
  • |???1?|??SORT?UNIQUE???????????????????????????|???????????????????????????????|?????1?|???159?|??4838?|???????|???????|??
  • |*??2?|???TABLE?ACCESS?BY?LOCAL?INDEX?ROWID????|?META_DBQL_TABLE_USAGE_EXP_HST?|?????1?|????67?|?????3?|???????|???????|??
  • |???3?|????NESTED?LOOPS????????????????????????|???????????????????????????????|?????1?|???159?|??4816?|???????|???????|??
  • |???4?|?????NESTED?LOOPS???????????????????????|???????????????????????????????|????18?|??1656?|??4762?|???????|???????|??
  • |???5?|??????PARTITION?RANGE?ITERATOR??????????|???????????????????????????????|?????1?|????56?|??4746?|???KEY?|????14?|??
  • |*??6?|???????TABLE?ACCESS?FULL????????????????|?META_DR_QRY_LOG_TGT_ALL_HST???|?????1?|????56?|??4746?|???KEY?|????14?|??
  • |???7?|??????PARTITION?RANGE?ITERATOR??????????|???????????????????????????????|????18?|???648?|????16?|???KEY?|????14?|??
  • |*??8?|???????TABLE?ACCESS?BY?LOCAL?INDEX?ROWID|?DR_QRY_LOG_EXP_HST????????????|????18?|???648?|????16?|???KEY?|????14?|??
  • |*??9?|????????<strong>INDEX?RANGE?SCAN????????????????|?DR_QRY_LOG_EXP_HST_IDX2</strong>???????|????31?|???????|????15?|???KEY?|????14?|??
  • |??10?|?????PARTITION?RANGE?ITERATOR???????????|???????????????????????????????|?????1?|???????|?????2?|???KEY?|???KEY?|??
  • |*?11?|??????INDEX?RANGE?SCAN??????????????????|?META_DBQL_TUSAGE_EHST_IDX?????|?????1?|???????|?????2?|???KEY?|???KEY?|??
  • ------------------------------------------------------------------------------------------------------------------------??
  • ??
  • Predicate?Information?(identified?by?operation?id):??
  • ---------------------------------------------------??
  • ??
  • ???2?-?filter((UPPER("TGT"."SYSTEMNAME")<>UPPER("SRC"."SYSTEMNAME")?OR??
  • ??????????????UPPER("TGT"."DATABASENAME")<>UPPER("SRC"."DATABASENAME")?OR?UPPER("TGT"."TABLENAME")<>UPPER("SRC"."TABLENAME"))??
  • ??????????????AND?"SRC"."SYSTEMNAME"="RL"."SYSTEMNAME")??
  • ???6?-?filter(UPPER("TGT"."SYSTEMNAME")='MOZART'?AND?UPPER("TGT"."DATABASENAME")='GDW_TABLES'?AND??
  • ??????????????UPPER("TGT"."TABLENAME")='SSA_SLNG_LSTG_MTRC_SD'?AND?"TGT"."ACCTSTRINGDATE">SYSDATE@!-30?AND?"TGT"."SYSTEMNAME"??
  • ??????????????IS?NOT?NULL?AND?"TGT"."DATABASENAME"?IS?NOT?NULL?AND?"TGT"."TABLENAME"?IS?NOT?NULL)??
  • ???8?-?filter("RL"."SYSTEMNAME"="TGT"."SYSTEMNAME")??
  • ???9?-?access("RL"."STATEMENT_ID"="TGT"."STATEMENT_ID"?AND?"RL"."ACCTSTRINGDATE">SYSDATE@!-30?AND??
  • ??????????????"RL"."ACCTSTRINGDATE"?IS?NOT?NULL)??
  • ??11?-?access("SRC"."QUERYID"="RL"."QUERYID"?AND?"SRC"."ACCTSTRINGDATE"="RL"."ACCTSTRINGDATE")??
  • ???????filter("SRC"."ACCTSTRINGDATE"="TGT"."ACCTSTRINGDATE"?AND?"SRC"."ACCTSTRINGDATE">SYSDATE@!-30)??

  • 從新的的執行計劃可以看出,它的第一個NESTED LOOP果然用了最新創建的索引。 下面是執行時間: [plain]? view plain copy print ?
  • 已用時間:??00:?00:?02.16??

  • 兩秒種搞定,遠遠超出他期望的5s :)

    方法總結

    NESTED LOOP高效的條件: 驅動數據源有限,且被驅動表在連接列上有相應的索引。

    總結

    以上是生活随笔為你收集整理的一个通过添加本地分区索引提高SQL性能的案例的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。