我的问题是关于我在使用INVISIBLE索引时看到的一个奇怪的执行计划。数据库11g
为特定查询的性能测试创建了两个不可见索引。
当我在没有任何提示和参数OPTIMIZER_USE_INVISIBLE_INDEXES = FALSE的情况下运行该查询时,查询正在进行预期的全表扫描并在148秒内返回行,并行度为21(下面的查询#1)
当我使用提示/ * + USE_INVISIBLE_INDEXES * /和参数OPTIMIZER_USE_INVISIBLE_INDEXES = TRUE运行该查询时,查询正在执行INDEX FAST FULL SCAN并在122秒内返回行,并行度为26(下面的查询#2)
当我通过命名名为hint / * + INDEX * /和参数OPTIMIZER_USE_INVISIBLE_INDEXES = TRUE的索引来运行该查询时,查询正在执行INDEX FULL SCAN和INDEX RANGE SCAN并且最大时间为649秒,并行度为13 (下面的查询#3)
d.o.p的趋势以及计划和执行时间仍然是这样,无论我运行查询的顺序如何。
很奇怪是否有人可以解释为什么命名索引导致最高的成本和返回时间?如果我必须使用索引,那么我必须命名它。在代码提升后使用提示/ * + USE_INVISIBLE_INDEXES * /不是一个选项。
指数:
CREATE INDEX INVOICELINE_IDX_PRF2
ON INVOICELINE (invoiceheaderid, chargetypeid, agreementid, unpaidamount)
INVISIBLE COMPUTE STATISTICS ;
CREATE INDEX INVOICEHEADER_IDX_PRF0
ON INVOICEHEADER (id, TRUNC(invoiceduedate))
INVISIBLE COMPUTE STATISTICS ;
提示:没有使用提示;全表扫描
输出时间:148秒
查询#1:
WITH V1
AS
(
SELECT
T1.agreementid AS agrmnt_id
,T1.invoicelineamount AS invc_line_amt
,TRUNC(T2.invoiceduedate) AS invc_due_dt
,T1.unpaidamount AS unpaid_amt
,T3.groupname AS grp_nm
FROM
INVOICELINE T1
,INVOICEHEADER T2
,CHARGETYPE T3
WHERE 1=1
AND T2.id = T1.invoiceheaderid
AND T3.id = T1.chargetypeid
)
SELECT /*+ PARALLEL(AUTO) */
agrmnt_id, invc_due_dt, SUM(unpaid_amt) AS sum_amount
FROM
V1
WHERE 1=1
AND UPPER(grp_nm)='INSTALMENT'
GROUP BY
agrmnt_id, invc_due_dt
;
执行计划:
----------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 6329 (100)| | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10003 | 1381K| 55M| | 6329 (6)| 00:00:01 | Q1,03 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 1381K| 55M| 68M| 6329 (6)| 00:00:01 | Q1,03 | PCWP | |
| 4 | PX RECEIVE | | 1381K| 55M| | 6329 (6)| 00:00:01 | Q1,03 | PCWP | |
| 5 | PX SEND HASH | :TQ10002 | 1381K| 55M| | 6329 (6)| 00:00:01 | Q1,02 | P->P | HASH |
| 6 | HASH GROUP BY | | 1381K| 55M| 68M| 6329 (6)| 00:00:01 | Q1,02 | PCWP | |
|* 7 | HASH JOIN | | 1381K| 55M| | 5804 (6)| 00:00:01 | Q1,02 | PCWP | |
| 8 | PX RECEIVE | | 1381K| 35M| | 3928 (7)| 00:00:01 | Q1,02 | PCWP | |
| 9 | PX SEND BROADCAST | :TQ10001 | 1381K| 35M| | 3928 (7)| 00:00:01 | Q1,01 | P->P | BROADCAST |
| 10 | VIEW | VW_GBC_13 | 1381K| 35M| | 3928 (7)| 00:00:01 | Q1,01 | PCWP | |
| 11 | HASH GROUP BY | | 1381K| 63M| 79M| 3928 (7)| 00:00:01 | Q1,01 | PCWP | |
| 12 | PX RECEIVE | | 1381K| 63M| | 3928 (7)| 00:00:01 | Q1,01 | PCWP | |
| 13 | PX SEND HASH | :TQ10000 | 1381K| 63M| | 3928 (7)| 00:00:01 | Q1,00 | P->P | HASH |
| 14 | HASH GROUP BY | | 1381K| 63M| 79M| 3928 (7)| 00:00:01 | Q1,00 | PCWP | |
|* 15 | HASH JOIN | | 1381K| 63M| | 3348 (8)| 00:00:01 | Q1,00 | PCWP | |
| 16 | JOIN FILTER CREATE | :BF0000 | 6 | 162 | | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
|* 17 | TABLE ACCESS STORAGE FULL | CHARGETYPE | 6 | 162 | | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 18 | JOIN FILTER USE | :BF0000 | 138M| 2766M| | 3324 (7)| 00:00:01 | Q1,00 | PCWP | |
| 19 | PX BLOCK ITERATOR | | 138M| 2766M| | 3324 (7)| 00:00:01 | Q1,00 | PCWC | |
|* 20 | TABLE ACCESS STORAGE FULL| INVOICELINE | 138M| 2766M| | 3324 (7)| 00:00:01 | Q1,00 | PCWP | |
| 21 | PX BLOCK ITERATOR | | 129M| 1857M| | 1855 (2)| 00:00:01 | Q1,02 | PCWC | |
|* 22 | TABLE ACCESS STORAGE FULL | INVOICEHEADER | 129M| 1857M| | 1855 (2)| 00:00:01 | Q1,02 | PCWP | |
----------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access(T2.ID=ITEM_1)
15 - access(T3.ID=T1.CHARGETYPEID)
17 - storage(UPPER(T3.GROUPNAME)=U'INSTALMENT')
filter(UPPER(T3.GROUPNAME)=U'INSTALMENT')
20 - storage(:Z>=:Z AND :Z<=:Z AND SYS_OP_BLOOM_FILTER(:BF0000,T1.CHARGETYPEID))
filter(SYS_OP_BLOOM_FILTER(:BF0000,T1.CHARGETYPEID))
22 - storage(:Z>=:Z AND :Z<=:Z)
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
- automatic DOP: Computed Degree of Parallelism is 21
提示:/ * + USE_INVISIBLE_INDEXES * /
输出时间:122秒
查询#2:
WITH V1
AS
(
SELECT /*+ USE_INVISIBLE_INDEXES */
T1.agreementid AS agrmnt_id
,T1.invoicelineamount AS invc_line_amt
,TRUNC(T2.invoiceduedate) AS invc_due_dt
,T1.unpaidamount AS unpaid_amt
,T3.groupname AS grp_nm
FROM
INVOICELINE T1
,INVOICEHEADER T2
,CHARGETYPE T3
WHERE 1=1
AND T2.id = T1.invoiceheaderid
AND T3.id = T1.chargetypeid
)
SELECT /*+ PARALLEL(AUTO) */
agrmnt_id, invc_due_dt, SUM(unpaid_amt) AS sum_amount
FROM
V1
WHERE 1=1
AND UPPER(grp_nm)='INSTALMENT'
GROUP BY
agrmnt_id, invc_due_dt
;
执行计划:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 1505 (100)| | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10003 | 1381K| 55M| | 1505 (7)| 00:00:01 | Q1,03 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 1381K| 55M| 68M| 1505 (7)| 00:00:01 | Q1,03 | PCWP | |
| 4 | PX RECEIVE | | 1381K| 55M| | 1505 (7)| 00:00:01 | Q1,03 | PCWP | |
| 5 | PX SEND HASH | :TQ10002 | 1381K| 55M| | 1505 (7)| 00:00:01 | Q1,02 | P->P | HASH |
| 6 | HASH GROUP BY | | 1381K| 55M| 68M| 1505 (7)| 00:00:01 | Q1,02 | PCWP | |
|* 7 | HASH JOIN | | 1381K| 55M| | 1082 (9)| 00:00:01 | Q1,02 | PCWP | |
| 8 | PX RECEIVE | | 1381K| 35M| | 815 (7)| 00:00:01 | Q1,02 | PCWP | |
| 9 | PX SEND BROADCAST | :TQ10001 | 1381K| 35M| | 815 (7)| 00:00:01 | Q1,01 | P->P | BROADCAST |
| 10 | VIEW | VW_GBC_13 | 1381K| 35M| | 815 (7)| 00:00:01 | Q1,01 | PCWP | |
| 11 | HASH GROUP BY | | 1381K| 63M| 79M| 815 (7)| 00:00:01 | Q1,01 | PCWP | |
| 12 | PX RECEIVE | | 1381K| 63M| | 815 (7)| 00:00:01 | Q1,01 | PCWP | |
| 13 | PX SEND HASH | :TQ10000 | 1381K| 63M| | 815 (7)| 00:00:01 | Q1,00 | P->P | HASH |
| 14 | HASH GROUP BY | | 1381K| 63M| 79M| 815 (7)| 00:00:01 | Q1,00 | PCWP | |
|* 15 | HASH JOIN | | 1381K| 63M| | 346 (15)| 00:00:01 | Q1,00 | PCWP | |
|* 16 | TABLE ACCESS STORAGE FULL | CHARGETYPE | 6 | 162 | | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 17 | PX BLOCK ITERATOR | | 138M| 2766M| | 326 (10)| 00:00:01 | Q1,00 | PCWC | |
|* 18 | INDEX STORAGE FAST FULL SCAN| INVOICELINE_IDX_PRF2 | 138M| 2766M| | 326 (10)| 00:00:01 | Q1,00 | PCWP | |
| 19 | PX BLOCK ITERATOR | | 129M| 1857M| | 250 (11)| 00:00:01 | Q1,02 | PCWC | |
|* 20 | INDEX STORAGE FAST FULL SCAN | INVOICEHEADER_IDX_PRF0 | 129M| 1857M| | 250 (11)| 00:00:01 | Q1,02 | PCWP | |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access(T2.ID=ITEM_1)
15 - access(T3.ID=T1.CHARGETYPEID)
16 - storage(UPPER(T3.GROUPNAME)=U'INSTALMENT')
filter(UPPER(T3.GROUPNAME)=U'INSTALMENT')
18 - storage(:Z>=:Z AND :Z<=:Z)
20 - storage(:Z>=:Z AND :Z<=:Z)
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
- automatic DOP: Computed Degree of Parallelism is 26
提示:/ * + INDEX(T1 INVOICELINE_IDX_PRF2)INDEX(T2 INVOICEHEADER_IDX_PRF0)* /
输出时间:649秒
查询#3:
WITH V1
AS
(
SELECT /*+ INDEX(T1 INVOICELINE_IDX_PRF2) INDEX(T2 INVOICEHEADER_IDX_PRF0) */
T1.agreementid AS agrmnt_id
,T1.invoicelineamount AS invc_line_amt
,TRUNC(T2.invoiceduedate) AS invc_due_dt
,T1.unpaidamount AS unpaid_amt
,T3.groupname AS grp_nm
FROM
INVOICELINE T1
,INVOICEHEADER T2
,CHARGETYPE T3
WHERE 1=1
AND T2.id = T1.invoiceheaderid
AND T3.id = T1.chargetypeid
)
SELECT /*+ PARALLEL(AUTO) */
agrmnt_id, invc_due_dt, SUM(unpaid_amt) AS sum_amount
FROM
V1
WHERE 1=1
AND UPPER(grp_nm)='INSTALMENT'
GROUP BY
agrmnt_id, invc_due_dt
;
执行计划:
----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 658K(100)| | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10002 | 1381K| 55M| | 658K (1)| 00:00:26 | Q1,02 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 1381K| 55M| 68M| 658K (1)| 00:00:26 | Q1,02 | PCWP | |
| 4 | PX RECEIVE | | 1381K| 55M| | 658K (1)| 00:00:26 | Q1,02 | PCWP | |
| 5 | PX SEND HASH | :TQ10001 | 1381K| 55M| | 658K (1)| 00:00:26 | Q1,01 | P->P | HASH |
| 6 | HASH GROUP BY | | 1381K| 55M| 68M| 658K (1)| 00:00:26 | Q1,01 | PCWP | |
| 7 | NESTED LOOPS | | 1381K| 55M| | 657K (1)| 00:00:26 | Q1,01 | PCWP | |
| 8 | VIEW | VW_GBC_11 | 1381K| 35M| | 302K (1)| 00:00:12 | Q1,01 | PCWP | |
| 9 | HASH GROUP BY | | 1381K| 63M| 79M| 302K (1)| 00:00:12 | Q1,01 | PCWP | |
| 10 | PX RECEIVE | | 1381K| 63M| | 302K (1)| 00:00:12 | Q1,01 | PCWP | |
| 11 | PX SEND HASH | :TQ10000 | 1381K| 63M| | 302K (1)| 00:00:12 | Q1,00 | P->P | HASH |
| 12 | HASH GROUP BY | | 1381K| 63M| 79M| 302K (1)| 00:00:12 | Q1,00 | PCWP | |
| 13 | NESTED LOOPS | | 1381K| 63M| | 301K (1)| 00:00:12 | Q1,00 | PCWP | |
| 14 | PX BLOCK ITERATOR | | | | | | | Q1,00 | PCWC | |
|* 15 | TABLE ACCESS STORAGE FULL| CHARGETYPE | 6 | 162 | | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
|* 16 | INDEX FULL SCAN | INVOICELINE_IDX_PRF2 | 222K| 4569K| | 50330 (1)| 00:00:02 | Q1,00 | PCWP | |
|* 17 | INDEX RANGE SCAN | INVOICEHEADER_IDX_PRF0 | 1 | 15 | | 0 (0)| | Q1,01 | PCWP | |
----------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
15 - storage(:Z>=:Z AND :Z<=:Z AND UPPER(T3.GROUPNAME)=U'INSTALMENT')
filter(UPPER(T3.GROUPNAME)=U'INSTALMENT')
16 - access(T3.ID=T1.CHARGETYPEID)
filter(T3.ID=T1.CHARGETYPEID)
17 - access(T2.ID=ITEM_1)
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
- automatic DOP: Computed Degree of Parallelism is 13
表计数
SAMPLE_SIZE LAST_ANALYZED
INVOICELINE Count = 138,145,934 71258201 04-JUN-18
INVOICEHEADER Count = 129,865,795 133224960 02-APR-19
CHARGETYPE Count = 620 597 15-JUN-18
嗯......我不能说我很惊讶。根据表行数,样本大小和最后分析的信息,我要说你最好的选择是至少分析INVOICELINE和CHARGETYPE表,如
BEGIN
DBMS_STATS.GATHER_TABLE_STATS('owner', 'INVOICEHEADER');
DBMS_STATS.GATHER_TABLE_STATS('owner', 'INVOICELINE');
DBMS_STATS.GATHER_TABLE_STATS('owner', 'CHARGETYPE');
END;
将上方的“所有者”更改为表格的正确所有者。
CHARGETYPE是一个非常小的桌子,可能不会影响很多东西,但它不会受到伤害。另一方面,INVOICELINE自上次分析以来,其尺寸几乎翻了一番 - 而且该分析是在九个月前进行的,因此这些统计数据可能非常陈旧。试试看。
每当我看到计划中发生奇怪的事情时,我的第一个问题始终是“所涉及的表格中的统计数据有多好?”。收集统计数据是非常安全的,并且不太可能产生任何负面影响,除了这些程序运行所需的时间,因此对于像这样的问题,它通常是一个良好的第一个攻击点。
祝你好运。