使用视图(&索引)优化SQL查询

时间:2017-01-04 16:54:13

标签: sql oracle optimization view

我很难优化sql查询,大约需要1分钟才能完成。这是查询:

SELECT mpg.ID_PROD_GARN, mpg.NO_PROD
FROM ACO.prime p
JOIN ACO.facture_compt fc
ON fc.id_factr = p.id_factr
JOIN ACO.V_CONTRAT vc
ON vc.NO_POLC = p.NO_POLC
JOIN ACO.MV_PRODUIT mp
ON mp.NO_PROD =vc.NO_PROD
JOIN ACO.MV_PROD_GARN mpg
ON mpg.NO_PROD   = mp.NO_PROD
WHERE p.id_prime =
( SELECT MAX(id_prime) AS prime FROM ACO.prime p WHERE p.no_polc='T3167978')
AND mpg.ID_PROD_GARN = '1238'
AND fc.cd_stat_factr = 'comp';

V_CONTRAT是一个视图,并且(如果我的理解是正确的)当以这种方式加入视图时,SQL正在通过所有行运行以查找结果。我做了一些研究,发现索引此视图可以加快我的查询速度。所以:

CREATE INDEX indx_no_produit ON ACO.V_CONTRAT(NO_PROD);

不幸的是我收到一条错误,说我无法索引视图SQL:ORA-01702:你不能在这里使用它。 *原因:除其他可能的原因外,如果出现此消息,将生成此消息            尝试在视图上定义版本视图。 *操作:只能在基表上创建版本视图。

所以我的问题是如何才能优雅地加快这个问题?

非常感谢提前!

编辑1:这是解释的计划

计划哈希值:3107129748

-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name                       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                            |     1 |   102 |       |   543K  (1)| 00:00:22 |
|   1 |  NESTED LOOPS                      |                            |     1 |   102 |       |   543K  (1)| 00:00:22 |
|   2 |   NESTED LOOPS                     |                            |     1 |    90 |       |   543K  (1)| 00:00:22 |
|   3 |    NESTED LOOPS                    |                            |     1 |    35 |       |     3   (0)| 00:00:01 |
|   4 |     NESTED LOOPS                   |                            |     1 |    14 |       |     2   (0)| 00:00:01 |
|   5 |      MAT_VIEW ACCESS BY INDEX ROWID| MV_PROD_GARN               |     1 |     9 |       |     1   (0)| 00:00:01 |
|*  6 |       INDEX UNIQUE SCAN            | PK_PROG                    |     1 |       |       |     1   (0)| 00:00:01 |
|   7 |      BITMAP CONVERSION TO ROWIDS   |                            |     1 |     5 |       |     1   (0)| 00:00:01 |
|*  8 |       BITMAP INDEX FAST FULL SCAN  | MV_PROD_NO_PROD_IDX        |       |       |       |            |          |
|   9 |     TABLE ACCESS BY INDEX ROWID    | PRIME                      |     1 |    21 |       |     1   (0)| 00:00:01 |
|* 10 |      INDEX UNIQUE SCAN             | PK_PRIME                   |     1 |       |       |     1   (0)| 00:00:01 |
|  11 |       SORT AGGREGATE               |                            |     1 |    15 |       |            |          |
|  12 |        FIRST ROW                   |                            |     1 |    15 |       |     1   (0)| 00:00:01 |
|* 13 |         INDEX RANGE SCAN (MIN/MAX) | PRIME_NO_POLC_IDX          |     1 |    15 |       |     1   (0)| 00:00:01 |
|* 14 |    VIEW                            | V_CONTRAT                  |     1 |    55 |       |   543K  (1)| 00:00:22 |
|  15 |     SORT UNIQUE                    |                            |    16M|  5011M|  2740M|   543K  (1)| 00:00:22 |
|  16 |      UNION-ALL                     |                            |       |       |       |            |          |
|* 17 |       HASH JOIN                    |                            |    16M|  2502M|       | 55963   (4)| 00:00:03 |
|  18 |        VIEW                        | index$_join$_016           |   103 |  1339 |       |     2   (0)| 00:00:01 |
|* 19 |         HASH JOIN                  |                            |       |       |       |            |          |
|  20 |          INDEX FAST FULL SCAN      | PK_PROD                    |   103 |  1339 |       |     1   (0)| 00:00:01 |
|  21 |          INDEX FAST FULL SCAN      | PRODUIT_COMBINE_IDX        |   103 |  1339 |       |     1   (0)| 00:00:01 |
|* 22 |        HASH JOIN RIGHT OUTER       |                            |    16M|  2293M|   261M| 55860   (4)| 00:00:03 |
|  23 |         INDEX FAST FULL SCAN       | ROL_INDEX1                 |    10M|   145M|       |  5703   (2)| 00:00:01 |
|* 24 |         HASH JOIN RIGHT OUTER      |                            |  6751K|   824M|   117M| 44540   (4)| 00:00:02 |
|  25 |          INLIST ITERATOR           |                            |       |       |       |            |          |
|* 26 |           INDEX RANGE SCAN         | ROL_CDROL_NOINTR_IDX       |  3975K|    72M|       |   756   (2)| 00:00:01 |
|* 27 |          HASH JOIN RIGHT OUTER     |                            |  4192K|   435M|    90M| 40898   (3)| 00:00:02 |
|* 28 |           TABLE ACCESS FULL        | ROLE                       |  2881K|    57M|       | 14553   (4)| 00:00:01 |
|* 29 |           HASH JOIN                |                            |  2941K|   246M|   104M| 24558   (3)| 00:00:01 |
|  30 |            INDEX FAST FULL SCAN    | INFO_BASE_DISTRIBUTEUR_FK1 |  4047K|    57M|       |  1925   (2)| 00:00:01 |
|* 31 |            HASH JOIN               |                            |  2961K|   206M|   136M| 20967   (3)| 00:00:01 |
|  32 |             TABLE ACCESS FULL      | CONTRAT_ITER               |  4088K|    89M|       | 12159   (2)| 00:00:01 |
|* 33 |             HASH JOIN RIGHT OUTER  |                            |  2961K|   141M|    32M|  7292   (3)| 00:00:01 |
|* 34 |              INDEX RANGE SCAN      | ROL_CDROL_NOINTR_IDX       |   933K|    22M|       |   890   (1)| 00:00:01 |
|* 35 |              TABLE ACCESS FULL     | CONTRAT                    |  2615K|    62M|       |  5781   (3)| 00:00:01 |
|* 36 |       HASH JOIN OUTER              |                            | 29239 |  2912K|       | 10228   (3)| 00:00:01 |
|* 37 |        HASH JOIN                   |                            | 29239 |  1941K|       |   285   (2)| 00:00:01 |
|  38 |         TABLE ACCESS FULL          | DISTRIBUTEUR               |  9142 | 91420 |       |    45   (3)| 00:00:01 |
|* 39 |         HASH JOIN                  |                            | 29239 |  1656K|       |   240   (1)| 00:00:01 |
|  40 |          INDEX FULL SCAN           | PRODUIT_COMBINE_IDX        |   103 |  1030 |       |     1   (0)| 00:00:01 |
|* 41 |          TABLE ACCESS FULL         | TPA_CONTRAT_MENSUEL        | 29239 |  1370K|       |   239   (1)| 00:00:01 |
|  42 |        TABLE ACCESS FULL           | COUNTERPARTY               |  3547K|   115M|       |  9921   (2)| 00:00:01 |
|* 43 |   INDEX RANGE SCAN                 | FACTURE_COMPT_INDEX9       |     1 |    12 |       |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------

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

   6 - access("MPG"."ID_PROD_GARN"=1238)
   8 - filter("MPG"."NO_PROD"="MP"."NO_PROD")
  10 - access("P"."ID_PRIME"= (SELECT MAX("ID_PRIME") FROM "ACO"."PRIME" "P" WHERE "P"."NO_POLC"='T3167978'))
  13 - access("P"."NO_POLC"='T3167978')
  14 - filter("VC"."NO_POLC"="P"."NO_POLC" AND "MP"."NO_PROD"="VC"."NO_PROD")
  17 - access("PROD"."NO_PROD"="ITER"."NO_PROD" AND "PROD"."NO_VERS_PROD"="ITER"."NO_VERS_PROD")
  19 - access(ROWID=ROWID)
  22 - access("ROLAUTRE"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLAUTRE"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
  24 - access("ROLA"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLA"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
  26 - access("ROLA"."CD_ROLE"(+)='ap' OR "ROLA"."CD_ROLE"(+)='debit' OR "ROLA"."CD_ROLE"(+)='emprun')
  27 - access("ROLPAY"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLPAY"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
  28 - filter("ROLPAY"."CD_ROLE"(+)='pay' AND "ROLPAY"."IND_PAY_PRI"(+)='1')
  29 - access("ITER"."ID_INFO_BASE"="IB"."ID_INFO_BASE" AND "ITER"."NO_ITER_CONT"="IB"."NO_ITER_CONT" AND 
              SYS_OP_DESCEND("ITER"."NO_ITER_CONT")=SYS_OP_DESCEND("IB"."NO_ITER_CONT"))
  31 - access("ITER"."ID_CONT"="CONT"."ID_CONT" AND "ITER"."NO_ITER_CONT"="CONT"."NO_DERN_ITER" AND 
              SYS_OP_DESCEND("ITER"."NO_ITER_CONT")=SYS_OP_DESCEND("CONT"."NO_DERN_ITER"))
  33 - access("ROLP"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLP"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
  34 - access("ROLP"."CD_ROLE"(+)='pren')
  35 - filter("CONT"."NO_SEQ_PROPO_SEL"=0)
  36 - access("CTRPY"."LAST_NAME"(+)="TCM"."CON_NOM_ASS_PRINC" AND 
              "CTRPY"."FRST_NAME"(+)="TCM"."CON_PRENOM_ASS_PRINC" AND "CTRPY"."DT_BIRTH"(+)="TCM"."CON_DATE_NAISS_ASS_PRINC")
  37 - access("TCM"."CON_NO_DISTRIBUTEUR"="A"."NO_DIST")
  39 - access("PROD"."NO_PROD"="TCM"."CON_CODE_PRODDUIT")
  41 - filter("TCM"."CON_VERSION_CONTRAT"=1)
  43 - access("FC"."ID_FACTR"="P"."ID_FACTR" AND "FC"."CD_STAT_FACTR"='comp')

编辑2:这是视图V_CONTRAT

    SELECT   DISTINCT cont.ID_CONT,
                     cont.NO_POLC,
                     cont.cd_divs,
                     prod.no_prod,
                     prod.cd_cie_encai,
                     prod.cd_faml_cptb,
                     ib.no_dist_init,
                     CASE
                        WHEN ROLP.ID_ROLE IS NOT NULL THEN ROLP.NO_INTR
                        WHEN rola.no_intr IS NOT NULL THEN rola.no_intr
                        WHEN rolpay.no_intr IS NOT NULL THEN rolpay.no_intr
                        ELSE rolAutre.no_intr
                     END
                        AS NO_INTR_PRINC,
                     rolpay.no_intr AS NO_INTR_PAY
     FROM                        VIRAGE.CONTRAT CONT
                              INNER JOIN
                                 VIRAGE.contrat_iter iter
                              ON     iter.id_cont = cont.id_cont
                                 AND ITER.NO_ITER_CONT = CONT.NO_DERN_ITER
                                 AND CONT.NO_SEQ_PROPO_SEL = 0
                           INNER JOIN
                              VIRAGE.info_base ib
                           ON iter.id_info_base = ib.id_info_base
                              AND iter.no_iter_cont = ib.no_iter_cont
                        INNER JOIN
                           VIRAGE.produit prod
                        ON prod.no_prod = iter.no_prod
                           AND prod.no_vers_prod = iter.no_vers_prod
                     LEFT JOIN
                        VIRAGE.role rolp
                     ON     rolp.id_cont = cont.id_cont
                        AND rolp.no_iter_cont = cont.no_dern_iter
                        AND rolp.cd_role = 'pren'
                  LEFT JOIN
                     VIRAGE.role rola
                  ON rola.id_cont = cont.id_cont
                     AND rola.no_iter_cont = cont.no_dern_iter
                     AND (   rola.cd_role = 'ap'
                          OR ROLA.CD_ROLE = 'debit'
                          OR rola.cd_role = 'emprun')
               LEFT JOIN
                  VIRAGE.role rolpay
               ON     rolpay.id_cont = cont.id_cont
                  AND rolpay.no_iter_cont = cont.no_dern_iter
                  AND rolpay.cd_role = 'pay'
                  AND rolpay.ind_pay_pri = '1'
            LEFT JOIN
               VIRAGE.role rolAutre
            ON rolAutre.id_cont = cont.id_cont
               AND rolAutre.no_iter_cont = cont.no_dern_iter
   UNION
   SELECT   DISTINCT
            CAST (tcm.con_sequence AS NUMBER (10, 0)) AS id_cont,
            CAST (tcm.con_numero_contrat AS VARCHAR2 (20)) AS no_polc,
            CAST (vd.cd_divs_compt AS VARCHAR2 (11)) AS cd_divs,
            CAST (tcm.con_code_prodduit AS NUMBER (5, 0)) AS no_prod,
            CAST (prod.cd_cie_encai AS VARCHAR2 (1)) AS cd_cie_encai,
            CAST (prod.cd_faml_cptb AS VARCHAR2 (11)) AS cd_faml_cptb,
            CAST (tcm.con_no_distributeur AS VARCHAR2 (15)) AS no_dist_init,
            CAST (ctrpy.no_ctrpy AS NUMBER) AS no_intr_princ,
            CAST (ctrpy.no_ctrpy AS NUMBER) AS no_intr_pay
     FROM            TPA.TPA_CONTRAT_MENSUEL tcm
                  INNER JOIN
                     VIRAGE.produit prod
                  ON prod.no_prod = tcm.con_code_prodduit
               LEFT JOIN
                  counterparty ctrpy
               ON     ctrpy.last_name = tcm.con_nom_ass_princ
                  AND ctrpy.frst_name = tcm.con_prenom_ass_princ
                  AND ctrpy.dt_birth = tcm.con_date_naiss_ass_princ
            INNER JOIN
               v_distributeur vd
            ON tcm.con_no_distributeur = vd.no_dist
            WHERE TCM.CON_VERSION_CONTRAT=1

1 个答案:

答案 0 :(得分:0)

索引只能在表格中创建。

确保为每个表中的每个外键创建索引。默认情况下,Oracle不像其他系统那样创建它们。

还检查子查询的性能,如果花费的时间太长,您还应该为WHERE子句中的每个属性创建索引。

不要忘记索引需要维护。