【发布时间】:2017-05-19 01:32:37
【问题描述】:
我很难优化大约需要 1 分钟才能完成的 sql 查询。这是查询:
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
【问题讨论】:
-
物化视图对您有帮助吗?对物化视图做一些研究。除了您可以在物化视图上拥有索引这一事实之外,“快速刷新”可能会有所帮助。如果您不是 DBA,则可能需要与您的 DBA 讨论。
-
在优化任何查询时,查询的解释计划是必须的。请运行
EXPLAIN PLAN FOR your_query,然后运行SELECT * FROM table( DBMS_xplan.Display ),最后复制整个上次查询的结果 - 并将其附加到问题作为纯文本 - 而不是位图!!! 。有关解释计划的更多信息,您可以在此处找到:docs.oracle.com/cd/B28359_01/server.111/b28274/… -
您不为视图编制索引 - 您需要在相关表的列上创建索引。
-
你有一些相当大的全表扫描。首先修复最严重的违规者(如果可能,索引适当的表列),然后查看结果。另外,看看DBMS_SQLTUNE
-
你能不能给出
V_CONTRATview 的定义?从解释计划来看,这个视图是这个查询中开销最大的。该视图正在对 1600 万行进行唯一排序,主查询仅从该视图中选择 1 行(1600 万行中的 1 行)。
标签: sql oracle optimization view