我是Oracle的新手,并且已经完成了改进当前在基于Web的应用程序中运行的一些现有SQL查询的任务。我已经提取了以下查询并在SQL Developer中运行它以查看Explain信息。我对计划表输出不太熟悉,并寻求一些帮助,可以改进查询性能,大约需要2秒才能返回50行。
查询:
SELECT PATD.StageName AS StageName,
100 * (LINKS.NEVENTS - LINKS.NCONTACTS) / (DECODE(LINKS.NEVENTS,0,1,LINKS.NEVENTS)) AS PERCENTREPEAT,
LINKS.NEVENTS AS NEVENTS,
LINKS.NCONTACTS AS NCONTACTS,
'STAGE' AS DETAILLEVEL,
LATD.LinkClassName AS LINKTYPE,
PATD.ActivityGroupTxt AS PACTIVITYGROUP,
SATD.ActivityGroupTxt AS SACTIVITYGROUP
FROM
(SELECT NEVENTS ,
NCONTACTS ,
LINKTYPEKEY ,
PACTIVITYGROUP ,
SACTIVITYGROUP
FROM
(SELECT SUM (
CASE
WHEN CALF.PredActivityKey = -1
THEN 0
ELSE 1
END) AS NEVENTS,
COUNT (DISTINCT CALF.RELATEDID) AS NCONTACTS,
CALF.predecessorlinkclasskey AS LINKTYPEKEY,
CALF.PredActivityKey AS PACTIVITYGROUP,
CALF.SuccActivityKey AS SACTIVITYGROUP
FROM
(SELECT * FROM TABLE_A WHERE GKEY = 4
) CALF
JOIN TABLE_B DDate
ON (DDate.DateKey=CALF.SegmentStartACDDateKey)
WHERE CALF.segmentstartacddate BETWEEN TO_DATE('2012-09-25', 'YYYY-MM-DD') AND TO_DATE('2013-09-25', 'YYYY-MM-DD')
AND DDate.fullDate BETWEEN TO_DATE('2012-09-25', 'YYYY-MM-DD') AND TO_DATE('2013-09-25', 'YYYY-MM-DD')
GROUP BY CALF.predecessorlinkclasskey,
CALF.PredActivityKey,
CALF.SuccActivityKey
ORDER BY NEVENTS DESC
)
WHERE ROWNUM <= 50
) LINKS
JOIN TABLE_C LATD
ON (LATD.linkclasskey=LINKS.LINKTYPEKEY)
JOIN TABLE_D PATD
ON (PATD.cfactivitykey=LINKS.PACTIVITYGROUP)
JOIN TABLE_D SATD
ON (SATD.cfactivitykey=LINKS.SACTIVITYGROUP)
计划表输出:
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 4550 | | 54882 (1)| 00:10:59 | | |
|* 1 | HASH JOIN | | 50 | 4550 | | 54882 (1)| 00:10:59 | | |
|* 2 | HASH JOIN | | 50 | 3850 | | 54855 (1)| 00:10:59 | | |
| 3 | MERGE JOIN | | 50 | 2550 | | 54829 (1)| 00:10:58 | | |
| 4 | TABLE ACCESS BY INDEX ROWID | TABLE_C | 3 | 39 | | 2 (0)| 00:00:01 | | |
| 5 | INDEX FULL SCAN | PK_TABLE_C | 3 | | | 1 (0)| 00:00:01 | | |
|* 6 | SORT JOIN | | 50 | 1900 | | 54827 (1)| 00:10:58 | | |
| 7 | VIEW | | 50 | 1900 | | 54826 (1)| 00:10:58 | | |
|* 8 | COUNT STOPKEY | | | | | | | | |
| 9 | VIEW | | 1244K| 45M| | 54826 (1)| 00:10:58 | | |
|* 10 | SORT ORDER BY STOPKEY | | 1244K| 45M| 61M| 54826 (1)| 00:10:58 | | |
| 11 | HASH GROUP BY | | 1244K| 45M| 61M| 54826 (1)| 00:10:58 | | |
| 12 | VIEW | VW_DAG_0 | 1244K| 45M| | 30184 (2)| 00:06:03 | | |
| 13 | HASH GROUP BY | | 1244K| 56M| 81M| 30184 (2)| 00:06:03 | | |
|* 14 | HASH JOIN | | 1244K| 56M| | 15278 (2)| 00:03:04 | | |
| 15 | TABLE ACCESS BY INDEX ROWID| TABLE_B | 367 | 5138 | | 15 (0)| 00:00:01 | | |
|* 16 | INDEX RANGE SCAN | AKI_TABLE_B | 367 | | | 2 (0)| 00:00:01 | | |
| 17 | PARTITION RANGE ITERATOR | | 1247K| 40M| | 15253 (2)| 00:03:04 | 40 | 92 |
| 18 | PARTITION HASH ALL | | 1247K| 40M| | 15253 (2)| 00:03:04 | 1 | 3 |
|* 19 | TABLE ACCESS FULL | TABLE_A | 1247K| 40M| | 15253 (2)| 00:03:04 | 118 | 276 |
| 20 | PARTITION LIST ALL | | 10183 | 258K| | 26 (0)| 00:00:01 | 1 | 4 |
| 21 | TABLE ACCESS FULL | TABLE_D | 10183 | 258K| | 26 (0)| 00:00:01 | 1 | 4 |
| 22 | PARTITION LIST ALL | | 10183 | 139K| | 26 (0)| 00:00:01 | 1 | 4 |
| 23 | TABLE ACCESS FULL | TABLE_D | 10183 | 139K| | 26 (0)| 00:00:01 | 1 | 4 |
-------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("SATD"."cfactivitykey"="LINKS"."SACTIVITYGROUP")
2 - access("PATD"."cfactivitykey"="LINKS"."PACTIVITYGROUP")
6 - access("LATD"."LINKCLASSKEY"="LINKS"."LINKTYPEKEY")
filter("LATD"."LINKCLASSKEY"="LINKS"."LINKTYPEKEY")
8 - filter(ROWNUM<=50)
10 - filter(ROWNUM<=50)
14 - access("DDATE"."DATEKEY"="TABLE_A"."SEGMENTSTARTACDDATEKEY")
16 - access("DDATE"."FULLDATE">=TO_DATE(' 2012-09-25 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "DDATE"."FULLDATE"<=TO_DATE('
2013-09-25 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
19 - filter("GKEY"=4 AND "TABLE_A"."SEGMENTSTARTACDDATE">=TO_DATE(' 2012-09-25 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
AND "TABLE_A"."SEGMENTSTARTACDDATE"<=TO_DATE(' 2013-09-25 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
Note
-----
- automatic DOP: skipped because of IO calibrate statistics are missing
49 rows selected
答案 0 :(得分:0)
这似乎是“分页”引起的经典性能问题。但是,我试图调查这个,因为这里提供了SQL和执行计划。
如果您搜索大约12个月左右的大窗口( BETWEEN '2012-09-25' AND '2013-09-25'
),CBO将遵循并依赖所有关键表的FTS。
但是,如果有适当的分区,那可能并不坏。 SQL可以非常快地返回(如果没有在期望的2秒内)。
你最昂贵的SQL操作是No 10&amp; 13计划输出(SORT ORDER和GROUP BY)。
|* 10 | SORT ORDER BY STOPKEY | | 1244K| 45M| 61M| 54826 (1)| 00:10:58 | | |
| 11 | HASH GROUP BY | | 1244K| 45M| 61M| 54826 (1)| 00:10:58 | | |
| 12 | VIEW | VW_DAG_0 | 1244K| 45M| | 30184 (2)| 00:06:03 | | |
| 13 | HASH GROUP BY | | 1244K| 56M| 81M| 30184 (2)| 00:06:03 | | |
因此,我建议如下(基于解释计划并假设STATS已更新):
在'TABLE_A'上1)全局索引以支持代价高昂的'..GROUP BY': -
CALF.predecessorlinkclasskey,
CALF.PredActivityKey,
CALF.SuccActivityKey
2)重新访问分区:重新组织表上的分区(也可能是子分区)(至少是最大的TABLE_A)以包含以下内容:
表-A: “GKEY”上的分区 “SEGMENTSTARTACDDATE”上的子分区
3)缩小日期范围窗口:我还建议您重新考虑并将日期范围窗口缩小到更现实和最佳的级别(可能是一个月或Qtr) 对于50行,没有必要遍历1247K行。
4)使用GTT停放临时输出(您可以尝试将其作为最后的手段。但是,这将需要代码重新分解/ SQL拆分等)
您可以尝试所有OR或其中一些选项。 确保您的统计信息(表/索引)是最新的。