当执行计划中出现BITMAP CONVERSION TO ROWIDS关键字时,需要注意了。

前言

前些天优化了一些耗费buffers较多的SQL,但系统CPU降低的效果不明显,于是又拉了awr报告,查看了SQL ordered by Gets排名前列的SQL。

分析

SQL代码:

select distinct pro5.value as CUSTOMERCODE,
                to_date('19000101000000', 'yyyymmddhh24miss') as LAST_UPDATE_TIME,
                pro2.value as NAME,
                nvl(pro3.value, '$$400006000004') as GENDER,
                decode(pro4.value,
                       '$$400003000001',
                       decode(length(trim(pro5.value)),
                              18,
                              substr(trim(pro5.value), 7, 8)),
                       null) as BIRTHDAY,
                decode(pro4.value, '$$400003000001', pro5.value, null) as CERT_NO,
                pro4.value as CERTIFICATE_TYPE,
                pro5.value as CERTIFICATE_NO,
                null as NATION,
                null as EFFECTIVE_DATE,
                null as EXPIRE_DATE
  from policy p
 inner join role r
    on p.topactualid = r.topactualid
   and r.kind = 'INSURANCECERTIFICATELIST'
 inner join property pro2
    on r.topactualid = pro2.topactualid
   and r.actualid = pro2.parentactualid
   and r.parentagreementid = pro2.parentagreementid
   and r.topagreementid = pro2.topagreementid
   and pro2.kind = 'CUSTOMERNAME'
 inner join property pro3
    on r.topactualid = pro3.topactualid
   and r.actualid = pro3.parentactualid
   and r.parentagreementid = pro3.parentagreementid
   and r.topagreementid = pro3.topagreementid
   and pro3.kind = 'PERSONSEX'
 inner join property pro4
    on r.topactualid = pro4.topactualid
   and r.actualid = pro4.parentactualid
   and r.parentagreementid = pro4.parentagreementid
   and r.topagreementid = pro4.topagreementid
   and pro4.kind = 'CERTIFICATETYPE'
 inner join property pro5
    on r.topactualid = pro5.topactualid
   and r.actualid = pro5.parentactualid
   and r.parentagreementid = pro5.parentagreementid
   and r.topagreementid = pro5.topagreementid
   and pro5.kind = 'CERTIFICATECODE' and pro5.value is not null
  left join endorsement e
    on p.endorsementid = e.endorsementid
 where p.productcode = '00070002'
   and p.currentflag = 'Y'
   and (p.uniquecode like '013100%' or p.uniquecode like '011000%')
   and ((p.policystatus = '$$900001103001') or
       (e.endorsementstatus = '$$900002106001' and
       e.ISSUEDATE > to_date('20160411', 'YYYYMMDD')))

执行计划:

Plan hash value: 3936231819

------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                    |     1 |   336 |   124K  (1)| 00:24:55 |
|   1 |  HASH UNIQUE                          |                    |     1 |   336 |   124K  (1)| 00:24:55 |
|   2 |   NESTED LOOPS                        |                    |     1 |   336 |   124K  (1)| 00:24:55 |
|   3 |    NESTED LOOPS                       |                    |     1 |   284 |   124K  (1)| 00:24:55 |
|   4 |     NESTED LOOPS                      |                    |     1 |   232 |   124K  (1)| 00:24:55 |
|   5 |      NESTED LOOPS                     |                    |    51 |  9180 |   124K  (1)| 00:24:50 |
|   6 |       NESTED LOOPS                    |                    | 14950 |  1868K| 11388   (1)| 00:02:17 |
|*  7 |        FILTER                         |                    |       |       |            |          |
|   8 |         NESTED LOOPS OUTER            |                    |   701 | 58183 |  6559   (1)| 00:01:19 |
|*  9 |          TABLE ACCESS FULL            | POLICY             |  2661 |   129K|  5834   (1)| 00:01:11 |
|  10 |          TABLE ACCESS BY INDEX ROWID  | ENDORSEMENT        |     1 |    33 |     1   (0)| 00:00:01 |
|* 11 |           INDEX UNIQUE SCAN           | ENDORSEMENT_PK     |     1 |       |     0   (0)| 00:00:01 |
|* 12 |        TABLE ACCESS BY INDEX ROWID    | ROLE               |    21 |   945 |    25   (0)| 00:00:01 |
|* 13 |         INDEX RANGE SCAN              | TC_ROLE66          |   453 |       |     4   (0)| 00:00:01 |
|* 14 |       TABLE ACCESS BY INDEX ROWID     | PROPERTY           |     1 |    52 |   124K  (1)| 00:24:50 |
|  15 |        BITMAP CONVERSION TO ROWIDS    |                    |       |       |            |          |
|  16 |         BITMAP AND                    |                    |       |       |            |          |
|  17 |          BITMAP CONVERSION FROM ROWIDS|                    |       |       |            |          |
|* 18 |           INDEX RANGE SCAN            | TC_PROPERTY_PARENT |    12 |       |     3   (0)| 00:00:01 |
|  19 |          BITMAP CONVERSION FROM ROWIDS|                    |       |       |            |          |
|* 20 |           INDEX RANGE SCAN            | TC_PROPERTY24      |    12 |       |     3   (0)| 00:00:01 |
|* 21 |      TABLE ACCESS BY INDEX ROWID      | PROPERTY           |     1 |    52 |    13   (0)| 00:00:01 |
|* 22 |       INDEX RANGE SCAN                | TC_PROPERTY_PARENT |    12 |       |     3   (0)| 00:00:01 |
|* 23 |     TABLE ACCESS BY INDEX ROWID       | PROPERTY           |     1 |    52 |     3   (0)| 00:00:01 |
|* 24 |      INDEX RANGE SCAN                 | TC_PROPERTY_PARENT |    12 |       |     3   (0)| 00:00:01 |
|* 25 |    TABLE ACCESS BY INDEX ROWID        | PROPERTY           |     1 |    52 |     3   (0)| 00:00:01 |
|* 26 |     INDEX RANGE SCAN                  | TC_PROPERTY_PARENT |    12 |       |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------

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

   7 - filter("P"."POLICYSTATUS"='$$900001103001' OR "E"."ENDORSEMENTSTATUS"='$$900002106001' AND 
              "E"."ISSUEDATE">TIMESTAMP' 2016-04-11 00:00:00')
   9 - filter("P"."PRODUCTCODE"='00070002' AND ("P"."UNIQUECODE" LIKE '013100%' OR "P"."UNIQUECODE" 
              LIKE '011000%') AND "P"."CURRENTFLAG"='Y')
  11 - access("P"."ENDORSEMENTID"="E"."ENDORSEMENTID"(+))
  12 - filter("R"."KIND"='INSURANCECERTIFICATELIST')
  13 - access("P"."TOPACTUALID"="R"."TOPACTUALID")
  14 - filter("PRO5"."VALUE" IS NOT NULL AND "PRO5"."KIND"='CERTIFICATECODE' AND 
              "R"."PARENTAGREEMENTID"="PRO5"."PARENTAGREEMENTID" AND "R"."TOPAGREEMENTID"="PRO5"."TOPAGREEMENTID")
  18 - access("R"."ACTUALID"="PRO5"."PARENTACTUALID")
  20 - access("R"."TOPACTUALID"="PRO5"."TOPACTUALID")
  21 - filter("PRO2"."KIND"='CUSTOMERNAME' AND "R"."TOPACTUALID"="PRO2"."TOPACTUALID" AND 
              "R"."PARENTAGREEMENTID"="PRO2"."PARENTAGREEMENTID" AND "R"."TOPAGREEMENTID"="PRO2"."TOPAGREEMENTID")
  22 - access("R"."ACTUALID"="PRO2"."PARENTACTUALID")
  23 - filter("PRO4"."KIND"='CERTIFICATETYPE' AND "R"."TOPACTUALID"="PRO4"."TOPACTUALID" AND 
              "R"."PARENTAGREEMENTID"="PRO4"."PARENTAGREEMENTID" AND "R"."TOPAGREEMENTID"="PRO4"."TOPAGREEMENTID")
  24 - access("R"."ACTUALID"="PRO4"."PARENTACTUALID")
  25 - filter("PRO3"."KIND"='PERSONSEX' AND "R"."TOPACTUALID"="PRO3"."TOPACTUALID" AND 
              "R"."PARENTAGREEMENTID"="PRO3"."PARENTAGREEMENTID" AND "R"."TOPAGREEMENTID"="PRO3"."TOPAGREEMENTID")
  26 - access("R"."ACTUALID"="PRO3"."PARENTACTUALID")

分析:

1)执行计划中 id = 15 关键字为BITMAP CONVERSION TO ROWIDS,此关键字在此之前都未遇见过,于是谷歌下,有了以下解释:

1)出现这样的情况,是因为表中存在不适当的索引,这些索引列的唯一度不高,oracle就有可能选择两个这样的索引转为bitmap来执行

2)根据这两个索引的值再确认共同有的ROWID,最后再通过ROWID回表提取符合条件的数据。

2) 可以使用/*+ opt_param('_b_tree_bitmap_plans','false') */hint 在sql级消除bitmap

3) 也可以删除选择率低的索引,建立复合索引进行改善

4) 根据执行计划的谓词信息,我建立了如下索引:

create index IDX_POLICY_01 on POLICY (PRODUCTCODE, CURRENTFLAG, UNIQUECODE);

create index IDX_PROPERTY_TEST02 on PROPERTY (KIND, PARENTACTUALID, TOPACTUALID, PARENTAGREEMENTID, TOPAGREEMENTID, VALUE) nologging;

5)建立索引后的执行计划:

Plan hash value: 2001935116

-----------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                     |     1 |   336 | 10938   (1)| 00:02:12 |
|   1 |  HASH UNIQUE                        |                     |     1 |   336 | 10938   (1)| 00:02:12 |
|   2 |   NESTED LOOPS                      |                     |     1 |   336 | 10937   (1)| 00:02:12 |
|   3 |    NESTED LOOPS                     |                     |     1 |   284 | 10934   (1)| 00:02:12 |
|   4 |     NESTED LOOPS                    |                     |     1 |   232 | 10931   (1)| 00:02:12 |
|   5 |      NESTED LOOPS                   |                     |     1 |   180 | 10928   (1)| 00:02:12 |
|   6 |       NESTED LOOPS                  |                     |   875 |   109K|  8301   (1)| 00:01:40 |
|*  7 |        FILTER                       |                     |       |       |            |          |
|   8 |         NESTED LOOPS OUTER          |                     |   300 | 24900 |  6500   (1)| 00:01:19 |
|*  9 |          TABLE ACCESS FULL          | POLICY              |  2776 |   135K|  5751   (1)| 00:01:10 |
|  10 |          TABLE ACCESS BY INDEX ROWID| ENDORSEMENT         |     1 |    33 |     1   (0)| 00:00:01 |
|* 11 |           INDEX UNIQUE SCAN         | ENDORSEMENT_PK      |     1 |       |     0   (0)| 00:00:01 |
|* 12 |        TABLE ACCESS BY INDEX ROWID  | ROLE                |     3 |   135 |     6   (0)| 00:00:01 |
|* 13 |         INDEX RANGE SCAN            | TC_ROLE66           |    62 |       |     3   (0)| 00:00:01 |
|* 14 |       INDEX RANGE SCAN              | IDX_PROPERTY_TEST02 |     1 |    52 |     3   (0)| 00:00:01 |
|* 15 |      INDEX RANGE SCAN               | IDX_PROPERTY_TEST02 |     1 |    52 |     3   (0)| 00:00:01 |
|* 16 |     INDEX RANGE SCAN                | IDX_PROPERTY_TEST02 |     1 |    52 |     3   (0)| 00:00:01 |
|* 17 |    INDEX RANGE SCAN                 | IDX_PROPERTY_TEST02 |     1 |    52 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

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

   7 - filter("P"."POLICYSTATUS"='$$900001103001' OR "E"."ENDORSEMENTSTATUS"='$$900002106001' AND 
              "E"."ISSUEDATE">TIMESTAMP' 2016-04-11 00:00:00')
   9 - filter("P"."PRODUCTCODE"='00070002' AND ("P"."UNIQUECODE" LIKE '013100%' OR 
              "P"."UNIQUECODE" LIKE '011000%') AND "P"."CURRENTFLAG"='Y')
  11 - access("P"."ENDORSEMENTID"="E"."ENDORSEMENTID"(+))
  12 - filter("R"."KIND"='INSURANCECERTIFICATELIST')
  13 - access("P"."TOPACTUALID"="R"."TOPACTUALID")
  14 - access("R"."ACTUALID"="PRO4"."PARENTACTUALID" AND "R"."TOPACTUALID"="PRO4"."TOPACTUALID" 
              AND "R"."PARENTAGREEMENTID"="PRO4"."PARENTAGREEMENTID" AND 
              "R"."TOPAGREEMENTID"="PRO4"."TOPAGREEMENTID" AND "PRO4"."KIND"='CERTIFICATETYPE')
  15 - access("R"."ACTUALID"="PRO3"."PARENTACTUALID" AND "R"."TOPACTUALID"="PRO3"."TOPACTUALID" 
              AND "R"."PARENTAGREEMENTID"="PRO3"."PARENTAGREEMENTID" AND 
              "R"."TOPAGREEMENTID"="PRO3"."TOPAGREEMENTID" AND "PRO3"."KIND"='PERSONSEX')
  16 - access("R"."ACTUALID"="PRO2"."PARENTACTUALID" AND "R"."TOPACTUALID"="PRO2"."TOPACTUALID" 
              AND "R"."PARENTAGREEMENTID"="PRO2"."PARENTAGREEMENTID" AND 
              "R"."TOPAGREEMENTID"="PRO2"."TOPAGREEMENTID" AND "PRO2"."KIND"='CUSTOMERNAME')
  17 - access("R"."ACTUALID"="PRO5"."PARENTACTUALID" AND "R"."TOPACTUALID"="PRO5"."TOPACTUALID" 
              AND "R"."PARENTAGREEMENTID"="PRO5"."PARENTAGREEMENTID" AND 
              "R"."TOPAGREEMENTID"="PRO5"."TOPAGREEMENTID" AND "PRO5"."KIND"='CERTIFICATECODE')
       filter("PRO5"."VALUE" IS NOT NULL)

优化后

建立索引后,sql从原来的450s降低到20s,buffers 消耗也显著降低。

posted @ 2018-04-25 17:26  DB-Engineer  阅读(1057)  评论(0编辑  收藏  举报