enable_index_filter

livehere0197發表於2023-11-18

前提

客戶反應現場有sql很慢,故拿來最佳化下。

慢sql

 select
 
                        proh.id                          ,
                        proh.receiveTime                 ,
                        b.main_send_dept                 ,
                        b.copy_send_dept                 ,
                        proh.rootproinstid               ,
                        proh.configId                    ,
                        proh.proDirId                    ,
                        proh.creator creatorId           ,
                        proh.createtime createTime       ,
                        pubh.config_code                 ,
                        proh.name proDefName             ,
                        config.name configName           ,
                        pubh.draft_deptname draftDeptName,
                        pubh.word_no wordno              ,
                        pubh.PUB_FORM_DATA_ID            ,
                        pubh.title                       ,
                        pubh.drafter_name creatorName    ,
                        pubh.LAST_MODIFY_TIME modifytime ,
                        WHW.PROINSTID                    ,
                        WHW.resourceId resourceId        ,
                        WHW.NAME                         ,
                        WHW.ACTDEFID                     ,
                        '1' isFinishedNUM                ,
                        WHW.CREATETIME currentUserTime   ,
                        WHW.USER_NAME                    ,
                        WHW.DEPT_NAME                    ,
                        WHW.actinstid                    ,
                        WHW.state                        ,
                        'true' isFinished                ,
                        wordno.wordno_year
                    
                from
                        (
                                SELECT DISTINCT
                                        WR.*,
                                        ww.createTime as receiveTime
                                FROM
                                        WFH_WORKITEM WW
                                LEFT JOIN WFH_PROCESS WR
                                ON
                                        WR.ID=WW.proinstid
                                left join
                                        (
                                                select
                                                        ww2.proinstid,
                                                        max(ww2.createtime) as createTime
                                                from
                                                        wfh_workitem ww2
                                                LEFT JOIN WFH_PROCESS WR
                                                ON
                                                        WR.ID=ww2.proinstid
                                                where
                                                        substr(ww2.full_dept_id, 1, 65) = 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a686949'
                                                    and WR.prodefid like 'fw\_%' ESCAPE '\'
                                                group by
                                                        ww2.proInstid
                                        )
                                        maxReceiveTime on ww.proinstid = maxReceiveTime.proinstid
                                WHERE
                                        substr(WW.full_dept_id, 1, 65) = 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a686949'
                                    and WR.prodefid like 'fw\_%' ESCAPE '\'
                                    and ww.createTime = maxReceiveTime.createtime
                        )
                        proh
                LEFT JOIN WFH_WORKITEM as WHW
                on
                        proh.ID=WHW.proinstid
                right join OA_PUB_FORM_DATA_HISTORY pubh
                on
                        pubh.pro_inst_id=WHW.proinstid
                left join
                        (
                                select id, main_send_dept, copy_send_dept from oa_form_fwzh
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwzhdw
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwfh
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwfhsm
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwglb
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwbs
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwbssm
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwfhdw
                                
                                union all
                                
                                select id, main_send_dept, copy_send_dept from oa_form_fwjjz
                        )
                        b
                on
                        pubh.PUB_FORM_DATA_ID=b.id
                left join OA_WORDNO_CONTAINER wordno
                on
                        pubh.pro_inst_id=wordno.pro_inst_id
                    and pubh.word_no    = wordno.WORDNO_FULL
                left join wfm_config config
                on
                        proh.proDefId = config.code
                where
                        WHW.createtime =
                        (
                                select
                                        max(C.createtime)
                                from
                                        WFH_WORKITEM as C
                                where
                                        WHW.proinstid=C.proinstid
                                group by
                                        C.proinstid
                        )   limit 10;

檢視此sql的執行計劃

1   #NSET2: [73992, 10, 1932] 
2     #PIPE2: [73992, 10, 1932] 
3       #PIPE2: [70141, 10, 1932] 
4         #PRJT2: [1676, 10, 1932]; exp_num(30), is_atom(FALSE) 
5           #TOPN2: [1676, 10, 1932]; top_num(10)
6             #SLCT2: [1676, 29754, 1932]; WHW.CREATETIME = exp48
7               #HASH RIGHT JOIN2: [1636, 1190174, 1932]; key_num(1), ret_null(0), KEY(config.code=proh.PRODEFID)
8                 #CSCN2: [1, 66, 96]; INDEX33556893(wfm_config as config)
9                 #HASH RIGHT JOIN2: [1274, 1190174, 1932]; key_num(2), ret_null(0), KEY(wordno.PRO_INST_ID=pubh.PRO_INST_ID AND wordno.WORDNO_FULL=pubh.WORD_NO)
10                  #SSCN: [66, 495334, 144]; i_OAWORDNOCONTAINER_lh(OA_WORDNO_CONTAINER as wordno)
11                  #HASH RIGHT JOIN2: [765, 1190174, 1932]; key_num(1), ret_null(0), KEY(b.id=pubh.PUB_FORM_DATA_ID)
12                    #PRJT2: [75, 58389, 144]; exp_num(3), is_atom(FALSE) 
13                      #UNION ALL: [75, 58389, 144]
14                        #PRJT2: [65, 58348, 144]; exp_num(3), is_atom(FALSE) 
15                          #UNION ALL: [65, 58348, 144]
16                            #PRJT2: [54, 53511, 144]; exp_num(3), is_atom(FALSE) 
17                              #UNION ALL: [54, 53511, 144]
18                                #PRJT2: [45, 53492, 144]; exp_num(3), is_atom(FALSE) 
19                                  #UNION ALL: [45, 53492, 144]
20                                    #PRJT2: [35, 53386, 144]; exp_num(3), is_atom(FALSE) 
21                                      #UNION ALL: [35, 53386, 144]
22                                        #PRJT2: [26, 53381, 144]; exp_num(3), is_atom(FALSE) 
23                                          #UNION ALL: [26, 53381, 144]
24                                            #PRJT2: [16, 53344, 144]; exp_num(3), is_atom(FALSE) 
25                                              #UNION ALL: [16, 53344, 144]
26                                                #PRJT2: [4, 12921, 144]; exp_num(3), is_atom(FALSE) 
27                                                  #UNION ALL: [4, 12921, 144]
28                                                    #PRJT2: [1, 12210, 144]; exp_num(3), is_atom(FALSE) 
29                                                      #CSCN2: [1, 12210, 144]; INDEX33557161(oa_form_fwzh)
30                                                    #PRJT2: [1, 711, 144]; exp_num(3), is_atom(FALSE) 
31                                                      #CSCN2: [1, 711, 144]; INDEX33557159(oa_form_fwzhdw)
32                                                #PRJT2: [5, 40423, 144]; exp_num(3), is_atom(FALSE) 
33                                                  #CSCN2: [5, 40423, 144]; INDEX33557171(oa_form_fwfh)
34                                            #PRJT2: [1, 37, 144]; exp_num(3), is_atom(FALSE) 
35                                              #CSCN2: [1, 37, 144]; INDEX33557167(oa_form_fwfhsm)
36                                        #PRJT2: [1, 5, 144]; exp_num(3), is_atom(FALSE) 
37                                          #CSCN2: [1, 5, 144]; INDEX33557165(oa_form_fwglb)
38                                    #PRJT2: [1, 106, 144]; exp_num(3), is_atom(FALSE) 
39                                      #CSCN2: [1, 106, 144]; INDEX33557177(oa_form_fwbs)
40                                #PRJT2: [1, 19, 144]; exp_num(3), is_atom(FALSE) 
41                                  #CSCN2: [1, 19, 144]; INDEX33557175(oa_form_fwbssm)
42                            #PRJT2: [1, 4837, 144]; exp_num(3), is_atom(FALSE) 
43                              #CSCN2: [1, 4837, 144]; INDEX33557169(oa_form_fwfhdw)
44                        #PRJT2: [1, 41, 144]; exp_num(3), is_atom(FALSE) 
45                          #CSCN2: [1, 41, 144]; INDEX33557163(oa_form_fwjjz)
46                    #HASH RIGHT JOIN2: [338, 1190174, 1788]; key_num(1), ret_null(0), KEY(WHW.PROINSTID=pubh.PRO_INST_ID)
47                      #INDEX JOIN LEFT JOIN2: [1, 20, 1440]  ret_null(0)
48                        #HEAP TABLE SCAN: [1, 1, 1440]; table_no(0), 
49                        #BLKUP2: [1, 20, 0]; IDX_WFH_WORKITEM_PROINSTID(WHW)
50                          #SSEK2: [1, 20, 0]; scan_type(ASC), IDX_WFH_WORKITEM_PROINSTID(wfh_workitem as WHW), scan_range[proh.ID,proh.ID]
51                      #CSCN2: [209, 1190174, 348]; INDEX33557101(oa_pub_form_data_history as pubh)
52        #SPL2: [68465, 20, 1848]; key_num(2), spool_num(0), is_atom(FALSE), has_variable(0) 
53          #PRJT2: [68465, 20, 1848]; exp_num(2), is_atom(FALSE) 
54            #PRJT2: [68465, 20, 1848]; exp_num(2), is_atom(FALSE) 
55              #HAGR2: [68465, 20, 1848]; grp_num(2), sfun_num(1); slave_empty(0) keys(C.PROINSTID, WHW.PROINSTID) 
56                #NEST LOOP INDEX JOIN2: [68396, 400, 1848] 
57                  #DISTINCT: [68391, 20, 1788]
58                    #HASH RIGHT JOIN2: [338, 1190174, 1788]; key_num(1), ret_null(0), KEY(WHW.PROINSTID=pubh.PRO_INST_ID)
59                      #INDEX JOIN LEFT JOIN2: [1, 20, 1440]  ret_null(0)
60                        #HEAP TABLE SCAN: [1, 1, 1440]; table_no(0), 
61                        #SSEK2: [1, 20, 0]; scan_type(ASC), IDX_WFH_WORKITEM_PROINSTID(wfh_workitem as WHW), scan_range[proh.ID,proh.ID]
62                      #CSCN2: [209, 1190174, 348]; INDEX33557101(oa_pub_form_data_history as pubh)
63                  #BLKUP2: [1, 20, 0]; IDX_WFH_WORKITEM_PROINSTID(C)
64                    #SSEK2: [1, 20, 0]; scan_type(ASC), IDX_WFH_WORKITEM_PROINSTID(wfh_workitem as C), scan_range[WHW.PROINSTID,WHW.PROINSTID]
65      #HEAP TABLE: [3850, 1, 1440]; table_no(0) full(FALSE), mpp_full(0) autoid(FALSE)
66        #PRJT2: [3850, 1, 1440]; exp_num(9), is_atom(FALSE) 
67          #DISTINCT: [3850, 1, 1440]
68            #SLCT2: [3845, 20, 1440]; (WW.FULL_DEPT_ID >= 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a686949' AND WW.FULL_DEPT_ID < 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a68694:' AND WW.PROINSTID = maxReceiveTime.proinstid AND WR.ID = WW.PROINSTID)
69              #NEST LOOP INDEX JOIN2: [3845, 20, 1440] 
70                #SLCT2: [3842, 20, 1332]; WR.PRODEFID LIKE 'fw\_%' ESCAPE '\'
71                  #NEST LOOP INDEX JOIN2: [3842, 20, 1332] 
72                    #PRJT2: [3841, 20, 204]; exp_num(2), is_atom(FALSE) 
73                      #HAGR2: [3841, 20, 204]; grp_num(1), sfun_num(1); slave_empty(0) keys(ww2.PROINSTID) 
74                        #SLCT2: [3728, 1226359, 204]; (ww2.FULL_DEPT_ID >= 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a686949' AND ww2.FULL_DEPT_ID < 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a68694:')
75                          #NEST LOOP INDEX JOIN2: [3728, 1226359, 204] 
76                            #SLCT2: [164, 61317, 96]; WR.PRODEFID LIKE 'fw\_%' ESCAPE '\'
77                              #SSCN: [164, 1226359, 96]; i_WFHPROCESS_lh(wfh_process as WR)
78                            #BLKUP2: [528, 20, 0]; IDX_WFH_WORKITEM_PROINSTID(ww2)
79                              #SSEK2: [528, 20, 0]; scan_type(ASC), IDX_WFH_WORKITEM_PROINSTID(wfh_workitem as ww2), scan_range[WR.ID,WR.ID]
80                    #BLKUP2: [1, 1, 0]; IDX_WFH_PROCESS_ID_VER(WR)
81                      #SSEK2: [1, 1, 0]; scan_type(ASC), IDX_WFH_PROCESS_ID_VER(wfh_process as WR), scan_range[(maxReceiveTime.proinstid,min),(maxReceiveTime.proinstid,max))
82                #BLKUP2: [1, 1, 0]; IDX_WFH_WORKITEM_CREATETIME(WW)
83                  #SSEK2: [1, 1, 0]; scan_type(ASC), IDX_WFH_WORKITEM_CREATETIME(wfh_workitem as WW), scan_range[maxReceiveTime.createTime,maxReceiveTime.createTime]

檢視ET

行號     OP         TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ---------- -------------------- ------- -------------------- ----------- -----------
1          PRJT2      0                    0%      72                   40          4
2          PRJT2      1                    0%      67                   36          4
3          PRJT2      1                    0%      67                   44          4
4          PRJT2      1                    0%      67                   30          4
5          PIPE2      1                    0%      67                   3           7
6          PIPE2      1                    0%      67                   2           7
7          PRJT2      2                    0%      63                   42          12
8          PRJT2      2                    0%      63                   38          4
9          SPL2       2                    0%      63                   52          1
10         PRJT2      2                    0%      63                   34          4
11         UNION_ALL2 4                    0%      62                   27          31
行號     OP         TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ---------- -------------------- ------- -------------------- ----------- -----------
12         PRJT2      5                    0%      61                   26          30
13         DLCK       6                    0%      59                   0           2
14         PRJT2      6                    0%      59                   66          28
15         PRJT2      8                    0%      58                   28          28
16         UNION_ALL2 9                    0%      57                   15          131
17         UNION_ALL2 10                   0%      53                   17          121
18         UNION_ALL2 10                   0%      53                   23          115
19         UNION_ALL2 10                   0%      53                   19          119
20         UNION_ALL2 10                   0%      53                   21          117
21         PRJT2      11                   0%      52                   32          84
22         PRJT2      13                   0%      50                   20          116
行號     OP         TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ---------- -------------------- ------- -------------------- ----------- -----------
23         PRJT2      13                   0%      50                   12          132
24         UNION_ALL2 14                   0%      49                   13          133
25         UNION_ALL2 15                   0%      46                   25          113
26         PRJT2      15                   0%      46                   4           6
27         PRJT2      15                   0%      46                   24          112
28         PRJT2      16                   0%      42                   18          118
29         PRJT2      16                   0%      42                   14          130
30         PRJT2      16                   0%      42                   22          114
31         PRJT2      16                   0%      42                   72          28
32         CSCN2      18                   0%      41                   37          2
33         PRJT2      19                   0%      40                   16          120
行號     OP    TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ----- -------------------- ------- -------------------- ----------- -----------
34         HSCN  24                   0%      39                   48          15
35         CSCN2 28                   0%      38                   41          2
36         CSCN2 58                   0%      37                   8           2
37         CSCN2 66                   0%      36                   45          2
38         CSCN2 78                   0%      35                   35          2
39         CSCN2 83                   0%      34                   39          2
40         NSET2 116                  0%      33                   1           4
41         CSCN2 411                  0%      32                   31          2
42         HRO2  1710                 0.02%   31                   7           22
43         CSCN2 2173                 0.02%   30                   43          6
44         HTAB  2266                 0.02%   29                   65          16
行號     OP    TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ----- -------------------- ------- -------------------- ----------- -----------
45         TOPN2 2873                 0.03%   28                   5           5
46         CSCN2 6593                 0.07%   27                   29          14
47         IJI2  6737                 0.07%   26                   71          36597
48         CSCN2 7733                 0.08%   25                   51          9
49         IJI2  13586                0.14%   24                   69          48778
50         CSCN2 19552                0.20%   23                   33          42
51         SLCT2 21453                0.22%   22                   70          24390
52         HRO2  25954                0.26%   21                   11          86
53         IJI2  29039                0.29%   20                   75          143991
54         SLCT2 39512                0.40%   19                   68          24390
55         HAGR2 91665                0.93%   18                   73          12209
行號     OP     TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ------ -------------------- ------- -------------------- ----------- -----------
56         DIST   96037                0.97%   17                   67          12209
57         SSCN   101904               1.03%   16                   10          497
58         IJLO2  103107               1.04%   15                   47          36597
59         BLKUP2 105687               1.07%   14                   80          48776
60         SLCT2  121906               1.24%   13                   76          1278
61         SSEK2  132649               1.34%   12                   81          24388
62         SSEK2  135139               1.37%   11                   83          24388
63         SLCT2  175588               1.78%   10                   74          60176
64         SSCN   207143               2.10%   9                    77          1228
65         SSEK2  221019               2.24%   8                    50          24388
66         HRO2   252654               2.56%   7                    46          12214
行號     OP     TIME(US)             PERCENT RANK                 SEQ         N_ENTER    
---------- ------ -------------------- ------- -------------------- ----------- -----------
67         BLKUP2 263793               2.67%   6                    82          48776
68         HRO2   269638               2.73%   5                    9           517
69         SSEK2  779557               7.90%   4                    79          95960
70         BLKUP2 1138279              11.53%  3                    49          48776
71         SLCT2  2360006              23.91%  2                    6           12
72         BLKUP2 3134386              31.76%  1                    78          191920

實驗1

根據分析,慢在此部分上

select
         ww2.proinstid,
         max(ww2.createtime) as createTime
 from
         wfh_workitem ww2
 LEFT JOIN WFH_PROCESS WR
 ON
         WR.ID=ww2.proinstid
 where
         substr(ww2.full_dept_id, 1, 65) = 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a686949'
     and WR.prodefid like 'fw\_%' ESCAPE '\'
 group by
         ww2.proInstid

再根據ET判斷時間浪費在BLKUP2回表上,第一個反應就是加聯合索引,達到消除聯合索引的效果。

CREATE  INDEX "i_wfh_workitem_lh" ON "OA_BOB"."wfh_workitem"(substr(full_dept_id, 1, 65),full_dept_id,proinstid,createtime) ;

可加入後速度並沒有加快很多,後發現是函式條件篩選率造成2個表產生hash關聯,而加入enable_hash_join(0)的hint後執行計劃又重新走IDX_WFH_WORKITEM_PROINSTID,強制走新加的索引,反而會慢。
既然走IDX_WFH_WORKITEM_PROINSTID,那麼可以再一步分析慢在哪裡,可以根據上面執行計劃看到走了IDX_WFH_WORKITEM_PROINSTID索引後BLKUP2回表,而後才進行SLCT2對FULL_DEPT_ID欄位進行篩選,問題就再這裡,那我們可以用hint讓篩選走到前面完成。

enable_index_filter

ENABLE_INDEX_FILTER說明:
預設0,動態會話級
是否進行索引過濾最佳化,可取值為 0、1、2。
0 不進行最佳化;
1 使用索引過濾最佳化,如果過濾條件涉及的列包含在索引中,那麼索引進行 SSEK2 後就可以使用此過濾條件,可以減少中間結果集。
2 在取值為 1 的基礎上,將 IN 查詢列表轉換為 HASH RIGHT SEMI JOIN。

試驗2

我們用一個簡單的語句來闡述此hint的作用,當我們有2個寬表,也就是欄位較多的表進行關聯,而select需要取很多欄位。

--例項語句
select * from tt2 t2 , tt1 t1 
where t2.d1 = t1.c1 and d3 < 100 and d1 < 50;
--執行計劃
1   #NSET2: [11, 4, 108] 
2     #PRJT2: [11, 4, 108]; exp_num(5), is_atom(FALSE) 
3       #HASH2 INNER JOIN: [11, 4, 108];  KEY_NUM(1); KEY(T2.D1=T1.C1) KEY_NULL_EQU(0)
4         #SLCT2: [10, 4, 56]; T2.D1 < 50
5           #BLKUP2: [10, 9900, 56]; IDX_ON_D3_TT2(T2) -- 總記錄100000
6             #SSEK2: [10, 9900, 56]; scan_type(ASC), IDX_ON_D3_TT2(TT2 as T2), scan_range(null2,100)
7         #SLCT2: [0, 49, 52]; T1.C1 < 50
8           #CSCN2: [0, 1000, 52]; INDEX33555613(TT1 as T1)

1.先SSEK2走IDX_ON_D3_TT2索引
2.BLKUP2回表
3.SLCT2再過濾d1 < 50

--複合索引(d3,d1)
create index idx_on_d3d1_tt2 on tt2(d3,d1);
--加hint
select /*+ ENABLE_INDEX_FILTER(1)*/ * 
from tt2 t2 join tt1 t1 on t2.d1 = t1.c1 
where d3 < 100 and d1 < 50;
--執行計劃
1   #NSET2: [2, 4, 108] 
2     #PRJT2: [2, 4, 108]; exp_num(5), is_atom(FALSE) 
3       #HASH2 INNER JOIN: [2, 4, 108];  KEY_NUM(1); KEY(T2.D1=T1.C1) KEY_NULL_EQU(0)
4         #BLKUP2: [1, 4, 56]; IDX_ON_D3D1_TT2(T2)
5           #SLCT2: [1, 4, 56]; T2.D1 < 50   -- 怎麼估算成4行
6             #SSEK2: [1, 4, 56]; scan_type(ASC), IDX_ON_D3D1_TT2(TT2 as T2), scan_range[(null2,min),(100,min))
7         #SLCT2: [0, 49, 52]; T1.C1 < 50
8           #CSCN2: [0, 1000, 52]; INDEX33555613(TT1 as T1)

成功利用複合索引,先索引快速掃描(d3<100),再在索引掃描後的基礎上繼續過濾(d1<50),接著回表查詢,最後才與t1做表連線查詢。

最終修改

慢的sql部分加入此hint

select   /*+enable_hash_join(0) enable_index_filter(1)*/    --加的部分
         ww2.proinstid,
         max(ww2.createtime) as createTime
 from
         wfh_workitem ww2
 LEFT JOIN WFH_PROCESS WR
 ON
         WR.ID=ww2.proinstid
 where
         substr(ww2.full_dept_id, 1, 65) = 'de4457db545b461bb359d3179adf50b4.775c477e6c0945d99b7083036a686949'
     and WR.prodefid like 'fw\_%' ESCAPE '\'
 group by
         ww2.proInstid

加入hint後,速度s級查出。


DM 武漢達夢資料庫股份有限公司

24小時免費服務熱線:400 991 6599

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70002866/viewspace-2996020/,如需轉載,請註明出處,否則將追究法律責任。