【數據庫】Oracle單表查詢性能優化 - 索引應用

目錄

問題說明

解決方案 - 場景A

解決方案 - 場景B

解決方案 - 場景C

深入理解索引 - 索引的邏輯結構

深入理解索引 - 索引的三個特點

深入理解索引 - 索引的注意事項


 

問題說明

系統上線後,用戶數據不斷增長,從最初的幾十萬記錄發展至上千萬、甚至上億條記錄。運維人員反饋原有的存儲過程運行效率愈發低下。review時發現以下可改進之處:

場景A:數據表的索引與查詢語句子條件(where)篩選字段無關,未合理創建索引; 

場景B:業務邏輯分析不足,產生非必要的表關聯,50%的語句可改寫爲單表查詢語句;

場景C:數據表本身已有相關索引,但在查詢時未正確使用索引

 


 

各場景解決方案:  由於不方便用項目代碼舉例,以下sql涉及的字段名、數據表名均用別名替換。

 

場景A:.必要表連接 + 無索引,可調整爲 必要表連接 + 索引檢索

表b:file_name,file_month,file_type(索引I:file_month)

表d: fee,file_name,file_month(無索引)

 

   SELECT fee

        FROM d

   WHERE file_name IN  (SELECT file_name FROM b WHERE file_month=202002 and file_type= 'XXX');

 

【執行計劃 - 必要表連接 + 無索引】

                              

優化分析】由於業務層面上,B與D表的file_month不等價,需保留表連接。執行計劃中的索引掃描“INDEX(FAST FULL SCAN)”用到了b表的索引I(file_month),可在 表d 的file_name列新建索引提升查詢性能。

新建索引】CREATE INDEX d_file_name_idx ON d (file_name) ;

執行計劃 - 必要表連接 + 索引檢索

                         

成本優化】:269416 --  1087

 


場景B非必要表連接  +  無索引 ,可調整爲 無表連接 + 索引檢索:

表c:file_name, file_month

表d:fee,file_name,file_month(數據量 3018488)

 

     SELECT fee

              FROM d 

      WHERE file_name IN (SELECT file_name FROM c WHERE file_month=202002);

 

執行計劃 - 非必要表連接  +  無索引 】:

                             

優化分析】d表的file_month與c表的file_month在業務層面是等價的,因此,c、d表無需關聯,並在file_month列建索引:

【無表連接】 

                   SELECT fee   

                                    FROM d 

                                   WHERE file_month= 202002;

 

執行計劃 - 無表連接  +  無索引

                             

 

【新建索引】       CREATE INDEX d_file_month_idx ON d (file_month) ;

執行計劃 - 無表連接  +  索引檢索
                             

成本優化】268758 - 267987 - 5

 


場景C:索引列嵌套函數,未合理使用索引

表d:amount, file_day(索引)

 

SELECT  dis_info_fee
              FROM d
              WHERE  ROUND(file_day/100)=202002;

【執行計劃 - 索引列嵌套函數】

                       

優化分析】表d的索引列file_day也在使用中嵌套了函數,數據查詢時無法使用索引,爲避免在索引列使用函數,需以業務邏輯爲基準改寫查詢方式。業務需求爲查詢當月的數據,故修改爲:

SELECT dis_info_fee
             FROM d
             WHERE file_day >= 202002*100+1 AND file_day < (202002+1)*100 

執行計劃 - 索引列無附加函數

                       

成本優化】268170 - 14930

 


深入理解索引:

1、索引的邏輯結構:

         

                                                   

索引的邏輯結構分爲三部分:Root(根塊)、Branch(莖塊)、Leaf(葉子塊)。

Leaf(葉子塊)存儲【 key column value(索引列具體值)+ 數據塊所在rowid】,即索引塊,當一個Leaf(葉子塊)存滿後,則開闢新空間,存儲到新的Leaf(葉子快),這時出現了兩個Leaf(葉子塊)的管理者 ---- Branch(莖塊)。

Branch(莖塊)存儲指向Leaf(葉子塊)的指針,當一個Branch(莖塊)存滿後,則開闢新空間,存儲到新的Branch(莖塊),這時出現了兩個Branch(莖塊)的管理者 ----  Root(根塊);

... ... ... ...

以此類推,索引的邏輯結構可一直往上堆疊,呈現“金字塔”結構。

由於索引塊只包含個別字段的信息,而數據塊包含數據表所有字段的信息,使用索引列查詢可提高查詢效率。

 

2、索引的三個特點:

a.索引高度較低:

b.索引存儲列值 + ROWID值,且 索引列取值可爲空

c.索引本身有序

 

以下示例仍以表d爲例, 數據量1.3億。表d:fee,cdr_seq(索引列)

 

2.1 特點a應用 :索引列 = 某一具體值                                                    

SELECT * 

             FROM d 

             WHERE cdr_seq = 'XXXXXXX';

【執行計劃】

                                  

按“金字塔”結構存儲索引,五百萬記錄,索引高度可能爲 兩 層;

                    500G數據包含幾百億條記錄,索引高度僅爲 六 層;

通過索引檢索一條數據只需完成(高度 + 1)次I/O操作。

需注意:查詢字段包括除索引列的字段時,會產生回表(TABLE ACCESS (BY INDEX ROWID)),增加 I/O開銷。

 

2.2 特點b應用 --- 統計函數 COUNT( ) / SUM( ) / AVG( )

SELECT COUNT(*)

                 FROM  d  ---  1.3億,58.84s

【執行計劃】

                                

 

SELECT COUNT(*)

                FROM  d 

                WHERE  cdr_seq  IS NOT NULL ---  1.3億,22.84s

【執行計劃】

                               

【成本優化】1086226 - 166539

本示例說明索引列取值可爲空,若指定索引字段取值非空,COUNT(*) / SUM(*) / AVG(*)函數可以通過索引字段統計信息,提高統計效率。

 

2.3 特點c應用 --- ORDER BY / DISTINCT 

SELECT  cdr_seq  

            FROM   d  

            WHERE cdr_seq  >= 1230201 ORDER BY cdr_seq  

【執行計劃 - 無索引】

 

 【執行計劃 - 索引檢索】

本示例說明新建索引後,因索引的有序性,可消除ORDER BY語句產生的排序(SORT (ORDER BY))

 

2.4 特點b/c綜合應用 --- 統計函數 MAX( ) / MIN( )

SELECT MAX(cdr_seq)

                      FROM d;

【執行計劃】

                  

本示例並未限定索引列非空,在執行計劃中仍然用到索引掃描,再次說明索引列可以取值爲空。另一方面,索引本身是有序的,在讀取最大值時,只需讀取最右邊葉子塊的最後一條記錄,即可獲得最大值。

 

綜上,總結四種索引掃描類型

  掃描類型 說明  
1 INDEX RANGE SCAN

局部掃描;                                返回記錄越少,效率越少;

索引列 = 具體取值
2 INDEX FAST FULL SCAN

全局掃描,一次讀取多個索引塊;本身無序,可能需要額外排序;

COUNT(),SUM(),AVG()
3 INDEX FAST SCAN

全局掃描,一次讀取一個索引塊;本身有序,可消除排序;

ORDER BY,DISTINCT
4 INDEX  FULL SCAN(MIN/MAX)

局部掃描,效率最高

MAX()只需讀取最右邊的葉子快;MN()只需讀取最左邊的葉子快;

 

3、使用索引的注意事項:

          a. 分區局部索引:若篩選條件只有索引字段,用不到分區字段,性能將會下降;

          b. 可通過組合索引避免回表(TABLE ACCESS by INDEX ROWID)造成的性能下降;

          c. 聚合因子越低 (表和索引兩者的排列順序相似度越高),排序計算量越低;

          d. 分析執行計劃時應關注成本(COST),必要時可用空間(BYTES)消耗換取成本(COST)優化;

          e. 不可在索引列嵌套函數;

          f. 根據業務場景精簡表結構字段;

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章