2013-10-24 52 views
1

我是Oracle的新手,并且已经完成了一项改进当前在基于Web的应用程序中运行的一些现有SQL查询的任务。我提取了以下查询并在SQL Developer中运行它以查看解释信息。我对“计划表输出”并不是很熟悉,并在查询性能方面寻求一些帮助,这些查询性能大约需要2秒才能返回50行。性能调优现有Oracle查询

查询:

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

那么你有一些全表扫描*可能*是一个问题。这些表中有多少行? – OldProgrammer

+0

查询选择一年的数据。不幸的是我没有DDL。 – user676567

回答

0

这似乎是因 '分页' 的经典性能问题。但是,我试图将此视为SQL和执行计划在这里提供的。 如果您搜索12个月左右的大窗口(BETWEEN '2012-09-25' AND '2013-09-25'),CBO将继续并依赖于所有关键表上的FTS。 但是,如果适当的分区已经到位,那可能不会那么糟糕。 SQL可以很快返回(如果不在所需的2秒内)。

您的SQL中最昂贵的操作是计划输出(排序顺序和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 |  |  |                                         

因此,我建议以下(基于解释计划和假设统计信息更新):

1)全球指数上 'TABLE_A' 支持昂贵的 '..GROUP BY': -

CALF.predecessorlinkclasskey, 
    CALF.PredActivityKey, 
    CALF.SuccActivityKey 

2)重新访问分区:重新组织分区(可以是表子分区以及)(至少最大TABLE_A),包括以下内容:

表-A:在“GKEY”的“SEGMENTSTARTACDDATE”

3)缩小日期范围窗口 子分区 分区:我也建议你重新思考和日期范围窗口减少到更逼真和最优化的水平(可能是一个月或一个Qtr) 手中没有任何一行要穿过1247K行50行。

4)使用GTT停放临时输出(你可以自己做个实验,作为最后的手段,但是,这将要求码重新分解/ SQL分裂等)

您可以尝试所有这些或部分选项。 确保您的统计信息(表格/索引)是最新的