如何阅读和分析Oracle解释计划?

时间:2019-03-19 15:29:54

标签: oracle oracle11g oracle10g sql-execution-plan explain

我已经为我的一个查询生成了一个解释计划。完整的解释计划如下所示

| Id  | Operation                                | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |                            |     1 |   202 |   441   (2)| 00:00:06 |
|   1 |  NESTED LOOPS OUTER                      |                            |     1 |   202 |   441   (2)| 00:00:06 |
|   2 |   NESTED LOOPS OUTER                     |                            |     1 |   192 |   441   (2)| 00:00:06 |
|   3 |    NESTED LOOPS OUTER                    |                            |     1 |   188 |   441   (2)| 00:00:06 |
|   4 |     NESTED LOOPS OUTER                   |                            |     1 |   185 |   441   (2)| 00:00:06 |
|   5 |      NESTED LOOPS OUTER                  |                            |     1 |   168 |   439   (2)| 00:00:06 |
|   6 |       NESTED LOOPS OUTER                 |                            |     1 |   159 |   438   (2)| 00:00:06 |
|*  7 |        FILTER                            |                            |       |       |            |          |
|   8 |         NESTED LOOPS OUTER               |                            |     1 |   153 |   437   (2)| 00:00:06 |
|   9 |          NESTED LOOPS OUTER              |                            |    47 |  6392 |   343   (3)| 00:00:05 |
|  10 |           NESTED LOOPS                   |                            |    46 |  6026 |   297   (3)| 00:00:04 |
|* 11 |            HASH JOIN OUTER               |                            |    46 |  5888 |   297   (3)| 00:00:04 |
|* 12 |             HASH JOIN                    |                            |    41 |  4961 |   294   (3)| 00:00:04 |
|* 13 |              HASH JOIN                   |                            |    41 |  4674 |   292   (3)| 00:00:04 |
|* 14 |               HASH JOIN OUTER            |                            |     3 |    24 |     3  (34)| 00:00:01 |
|  15 |                INDEX FULL SCAN           | COM_DOCUMENT_TYPES_PK      |     3 |     9 |     1   (0)| 00:00:01 |
|* 16 |                INDEX FULL SCAN           | COM_DOCUMENT_TYPES_MLD_PK  |     3 |    15 |     1   (0)| 00:00:01 |
|* 17 |               TABLE ACCESS BY INDEX ROWID| COM_DOCUMENTS              |    41 |  4346 |   289   (3)| 00:00:04 |
|* 18 |                INDEX RANGE SCAN          | COM_DOCUMENTS_IDX2         |  8064 |       |    17   (6)| 00:00:01 |
|  19 |              TABLE ACCESS BY INDEX ROWID | WF_PROCESS_STATUS          |     5 |    35 |     2   (0)| 00:00:01 |
|* 20 |               INDEX RANGE SCAN           | WF_PROCESS_STATUS_IDX1     |     5 |       |     1   (0)| 00:00:01 |
|* 21 |             TABLE ACCESS FULL            | WF_PROCESS_STATUS_MLD      |    24 |   168 |     2   (0)| 00:00:01 |
|* 22 |            INDEX UNIQUE SCAN             | SYS_C0021772               |     1 |     3 |     0   (0)| 00:00:01 |
|* 23 |           INDEX RANGE SCAN               | COM_MUNICIPAL_LICENSE_IDX2 |     1 |     5 |     1   (0)| 00:00:01 |
|  24 |          TABLE ACCESS BY INDEX ROWID     | LCT_SPONSOR                |     1 |    17 |     2   (0)| 00:00:01 |
|* 25 |           INDEX UNIQUE SCAN              | LCT_SPONSOR_PK             |     1 |       |     1   (0)| 00:00:01 |
|* 26 |        INDEX UNIQUE SCAN                 | AUTH_USERS_PK              |     1 |     6 |     1   (0)| 00:00:01 |
|* 27 |       INDEX UNIQUE SCAN                  | AUTH_USERS_MLD_UK1         |     1 |     9 |     1   (0)| 00:00:01 |
|  28 |      TABLE ACCESS BY INDEX ROWID         | LCT_SPONSOR_BRANCHES       |     1 |    17 |     2   (0)| 00:00:01 |
|* 29 |       INDEX UNIQUE SCAN                  | BRANCHES_ID1               |     1 |       |     1   (0)| 00:00:01 |
|* 30 |     INDEX UNIQUE SCAN                    | LCM_REGION_PK              |     1 |     3 |     0   (0)| 00:00:01 |
|* 31 |    INDEX UNIQUE SCAN                     | LCM_WILAYAT_PK             |     1 |     4 |     0   (0)| 00:00:01 |
|* 32 |   INDEX UNIQUE SCAN                      | LCM_VILLAGE_PK             |     1 |    10 |     0   (0)| 00:00:01 |

下面给出了完整的查询查询,供您参考:

SET SERVEROUTPUT ON;
DECLARE
    CR VARCHAR2(32767) := '1048830';
    DUID VARCHAR2(32767) := '1048830-10804-7174-72';
    ST NUMBER := 105;
    DTID NUMBER := 2;
    RESP VARCHAR2(32767);
BEGIN
    SELECT D.*
    FROM COM_DOCUMENTS D
    INNER JOIN SYS_LABOUR_OFFICE LO ON D.LABOUR_OFFICE_ID=LO.ID
    LEFT JOIN COM_MUNICIPAL_LICENSE ML ON D.ID = ML.DOCUMENT_ID
    LEFT JOIN LCT_SPONSOR SP ON D.SPONSOR_NO = SP.SPONSOR_NO
    LEFT JOIN LCT_SPONSOR_BRANCHES LSB ON D.BRANCH_NO =LSB.ID
    INNER JOIN WF_PROCESS_STATUS PS ON D.CURRENT_STATUS_ID = PS.WF_PROCESS_STATUS_ID AND PS.WF_PROCESS_ID = 6
    LEFT JOIN WF_PROCESS_STATUS_MLD PSMLD ON PS.WF_PROCESS_STATUS_ID = PSMLD.WF_PROCESS_STATUS_ID AND PSMLD.LANGUAGE_ID = 1 
    LEFT JOIN AUTH_USERS AU1 ON D.CURRENT_FOLLOWER = AU1.USER_ID
    LEFT JOIN AUTH_USERS_MLD AU_MLD1 ON AU1.USER_ID = AU_MLD1.USER_ID AND AU_MLD1.LANGUAGE_ID = 1
    INNER JOIN COM_DOCUMENT_TYPES DT ON D.DOC_TYPE_ID = DT.DOCUMENT_TYPE_ID
    LEFT JOIN COM_DOCUMENT_TYPES_MLD DTM ON DT.DOCUMENT_TYPE_ID = DTM.DOCUMENT_TYPE_ID AND DTM.LANGUAGE_ID=1
    LEFT JOIN LCM_REGION LR ON LSB.REGION_CODE = LR.REGION_CODE
    LEFT JOIN LCM_WILAYAT LW ON LSB.REGION_CODE = LW.REGION_CODE AND LSB.WILAYAT_CODE = LW.WILAYAT_CODE
    LEFT JOIN LCM_VILLAGE LV ON LSB.REGION_CODE = LV.REGION_CODE AND LSB.WILAYAT_CODE = LV.WILAYAT_CODE AND LSB.VILLAGE_CODE = LV.VILLAGE_CODE
    WHERE (CR = '' OR SP.CR_NO =  CR)
    AND (DUID = '' OR D.DOC_UNIQUE_IDENTIFIER = NVL(DUID,  D.DOC_UNIQUE_IDENTIFIER))
    AND (ST = -99 OR D.CURRENT_STATUS_ID =  ST)
    AND (DTID = -99 OR D.DOC_TYPE_ID =  DTID);

    DBMS_OUTPUT.PUT_LINE(RESP);
END;

我对oracle非常陌生,我需要了解如何阅读此解释计划。

我实际上需要了解如何通过阅读解释计划来优化查询和加入订单等。希望这对很多人有帮助。

1 个答案:

答案 0 :(得分:0)

我会这样开始。 表是否已分区并且对哪些列进行了索引? 这些表是否有最新统计信息?甲骨文拥有做出明智选择所需的一切吗? 我是否要删除/截断分区并使用append将其插入/插入这些表中,因为如果我使用带有insert的插入进行删除,HWM会成为一个问题。

您想要的是拥有Oracle,做出正确的执行计划选择。您需要表,分区和索引具有最新的统计信息。

begin
    DBMS_STATS.GATHER_TABLE_STATS
    (OWNNAME            => lv_schema_from, 
     TABNAME            => lv_table_from, 
     ESTIMATE_PERCENT   => 15,     --15% for ~100000 of record, 15%-100% for less         METHOD_OPT         => 'FOR ALL COLUMNS SIZE AUTO', 
     GRANULARITY        => 'AUTO', --only if you have partitioned table
     DEGREE             => 8,      --parallel 
     CASCADE            => TRUE);  --cascade to indexes
end;

这可能会改变执行计划(更好)。

然后,如果是相同的执行计划,我将从表和并行提示之间的联接类型开始(有多少个内核可用?)。

哪个更好?首先从D或LO读取->在表的最小表上进行前导提示,它们之间具有内部联接(以防万一)。

我要使用索引吗?如果我使用索引将9.000.000条记录查找到300.000.000表(3%)中,则可能需要半小时。就我而言,use_hash或完整提示比让oracle进行索引要快。

实验...不同数量的内核,PGA,SGA,统计数据(最重要)使CBO对同一查询的最佳执行计划进行不同的评估。

最好的方法是找到问题的根源,这将是为什么Oracle为什么选择此执行计划的答案? 大多数时候,表,分区和索引的统计信息。