Oracle execution plan explanation (2)

Now let's talk about the meaning of each parameter in the oracle execution plan
Let's illustrate with an example below
To add this, there are several types of trace s
Sequence Number command explain
1 SET AUTOTRACE OFF This is the default value, which turns off Autotrace
2 SET AUTOTRACE ON EXPLAIN Show only execution plans
3 SET AUTOTRACE ON STATISTICS Show execution statistics only
4 SET AUTOTRACE ON Contains 2,3 items
5 SET AUTOTRACE TRACEONLY Similar to ON, but does not show the execution result of the statement

I like SET AUTOTRACE TRACEONLY, and our future examples are based on this approach
view plaincopy
  1. SQL> select * from departments a where a.department_id in (select b.department_id from employees b where b.employee_id=205);    
  2.     
  3.     
  4. Execution Plan    
  5. ----------------------------------------------------------    
  6. Plan hash value: 2782876085    
  7.     
  8. ----------------------------------------------------------------------------------------------    
  9. | Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time     |    
  10. ----------------------------------------------------------------------------------------------    
  11. |   0 | SELECT STATEMENT             |               |     1 |    27 |     2   (0)| 00:00:01 |    
  12. |   1 |  NESTED LOOPS                |               |     1 |    27 |     2   (0)| 00:00:01 |    
  13. |   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |    
  14. |*  3 |    INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |    
  15. |   4 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS   |    27 |   540 |     1   (0)| 00:00:01 |    
  16. |*  5 |    INDEX UNIQUE SCAN         | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |    
  17. ----------------------------------------------------------------------------------------------    
  18.     
  19. Predicate Information (identified by operation id):    
  20. ---------------------------------------------------    
  21.     
  22.    3 - access("B"."EMPLOYEE_ID"=205)    
  23.    5 - access("A"."DEPARTMENT_ID"="B"."DEPARTMENT_ID")    
  24.     
  25.     
  26. Statistics    
  27. ----------------------------------------------------------    
  28.           1  recursive calls    
  29.           0  db block gets    
  30.           4  consistent gets    
  31.           0  physical reads    
  32.           0  redo size    
  33.         749  bytes sent via SQL*Net to client    
  34.         492  bytes received via SQL*Net from client    
  35.           2  SQL*Net roundtrips to/from client    
  36.           0  sorts (memory)    
  37.           0  sorts (disk)    
  38.           1  rows processed   
SQL> select * from departments a where a.department_id in (select b.department_id from employees b where b.employee_id=205);  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 2782876085  
  
----------------------------------------------------------------------------------------------  
| Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
----------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT             |               |     1 |    27 |     2   (0)| 00:00:01 |  
|   1 |  NESTED LOOPS                |               |     1 |    27 |     2   (0)| 00:00:01 |  
|   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |  
|*  3 |    INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
|   4 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS   |    27 |   540 |     1   (0)| 00:00:01 |  
|*  5 |    INDEX UNIQUE SCAN         | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |  
----------------------------------------------------------------------------------------------  
  
Predicate Information (identified by operation id):  
---------------------------------------------------  
  
   3 - access("B"."EMPLOYEE_ID"=205)  
   5 - access("A"."DEPARTMENT_ID"="B"."DEPARTMENT_ID")  
  
  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
          4  consistent gets  
          0  physical reads  
          0  redo size  
        749  bytes sent via SQL*Net to client  
        492  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
          1  rows processed 

  
Let's look at it line by line:
I. Table Part
1,Plan hash value:
[sql] view plaincopy
Plan hash value: 2782876085 
This line is the hash value of this statement, and we know that the execution plan generated by oracle for each statement is placed in the share pool, which is hard parsed for the first time to produce a hash value.Compare hash values the next time you execute the statement, and do not perform hard resolution if they are the same.
2. Operation
There are so many things here, just break up sql and let me see sql on it. The first step of this sql is employee_id=25. Here we have a primary key on employee_id, which creates a unique index by default.This is restricted by'=', so go unique scan.Other ways to refer to Oracle execution plan explanation (1) content
Another point to learn about table linking is my other article ()
3. Name (object being manipulated)
For example, the second line of operation in the example above (TABLE ACCESS BY INDEX ROWID) where the TABLE object is EMPLOYEES
4. Row, sometimes called Cardinality (use plsqldev to explain the plan window)
Here is the number of rows in the data query, such as row 4 in the previous example. The department table scans 27 rows and compares them with the value of the subquery (select b.department_id from employees b where b.employee_id=205).If you use = (Note: most of the time you can't replace with =, this is a special case) it will be different.
[sql] view plaincopy
  1. SQL> select * from departments a where a.department_id = (select b.department_id from employees b where b.employee_id=205);    
  2.     
  3.     
  4. Execution Plan    
  5. ----------------------------------------------------------    
  6. Plan hash value: 3449260133    
  7.     
  8. -----------------------------------------------------------------------------------------------    
  9. | Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |    
  10. -----------------------------------------------------------------------------------------------    
  11. |   0 | SELECT STATEMENT              |               |     1 |    20 |     2   (0)| 00:00:01 |    
  12. |   1 |  TABLE ACCESS BY INDEX ROWID  | DEPARTMENTS   |     1 |    20 |     1   (0)| 00:00:01 |    
  13. |*  2 |   INDEX UNIQUE SCAN           | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |    
  14. |   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |    
  15. |*  4 |     INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |    
  16. -----------------------------------------------------------------------------------------------    
  17.     
  18. Predicate Information (identified by operation id):    
  19. ---------------------------------------------------    
  20.     
  21.    2 - access("A"."DEPARTMENT_ID"= (SELECT /*+ */ "B"."DEPARTMENT_ID" FROM "EMPLOYEES"    
  22.               "B" WHERE "B"."EMPLOYEE_ID"=205))    
  23.    4 - access("B"."EMPLOYEE_ID"=205)    
  24.     
  25.     
  26. Statistics    
  27. ----------------------------------------------------------    
  28.           0  recursive calls    
  29.           0  db block gets    
  30.           4  consistent gets    
  31.           0  physical reads    
  32.           0  redo size    
  33.         749  bytes sent via SQL*Net to client    
  34.         492  bytes received via SQL*Net from client    
  35.           2  SQL*Net roundtrips to/from client    
  36.           0  sorts (memory)    
  37.           0  sorts (disk)    
  38.           1  rows processed    
  39.      
SQL> select * from departments a where a.department_id = (select b.department_id from employees b where b.employee_id=205);  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 3449260133  
  
-----------------------------------------------------------------------------------------------  
| Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
-----------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT              |               |     1 |    20 |     2   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS BY INDEX ROWID  | DEPARTMENTS   |     1 |    20 |     1   (0)| 00:00:01 |  
|*  2 |   INDEX UNIQUE SCAN           | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |  
|   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |  
|*  4 |     INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
-----------------------------------------------------------------------------------------------  
  
Predicate Information (identified by operation id):  
---------------------------------------------------  
  
   2 - access("A"."DEPARTMENT_ID"= (SELECT /*+ */ "B"."DEPARTMENT_ID" FROM "EMPLOYEES"  
              "B" WHERE "B"."EMPLOYEE_ID"=205))  
   4 - access("B"."EMPLOYEE_ID"=205)  
  
  
Statistics  
----------------------------------------------------------  
          0  recursive calls  
          0  db block gets  
          4  consistent gets  
          0  physical reads  
          0  redo size  
        749  bytes sent via SQL*Net to client  
        492  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
          1  rows processed  
   

5,Byte
Bytes of scanned data
6,Cost
Last time we talked about it here, let's put it in a nutshell.
Cost has no unit, is a relative value, is used by oracle to evaluate cbo cost and select execution plan when sql parses execution in cbo mode.
Formula: Cost=(Single block I/O cost+ Multiblock I/O cost+; CPU cost)/sreadtim
It doesn't have a clear meaning, but it's useful for comparison.
7,Time
Time of each execution

2. Predicate Information
There are two types of filter conditions listed here:
1. Index (access)
As in the access("B"."EMPLOYEE_ID"=205) example above, an index is used here as the filter condition
2. Non-index (filter), see the following example
[sql] view plaincopy
  1. SQL> select employee_id    
  2.                   from employees c    
  3.                  where c.first_name = 'Steven'   2    3  ;    
  4.     
  5.     
  6. Execution Plan    
  7. ----------------------------------------------------------    
  8. Plan hash value: 1445457117    
  9.     
  10. -------------------------------------------------------------------------------    
  11. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |    
  12. -------------------------------------------------------------------------------    
  13. |   0 | SELECT STATEMENT  |           |     1 |    11 |     3   (0)| 00:00:01 |    
  14. |*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |    11 |     3   (0)| 00:00:01 |    
  15. -------------------------------------------------------------------------------    
  16.     
  17. Predicate Information (identified by operation id):    
  18. ---------------------------------------------------    
  19.     
  20.    1 - filter("C"."FIRST_NAME"='Steven')    
  21.     
  22.     
  23. Statistics    
  24. ----------------------------------------------------------    
  25.           1  recursive calls    
  26.           0  db block gets    
  27.           8  consistent gets    
  28.           0  physical reads    
  29.           0  redo size    
  30.         574  bytes sent via SQL*Net to client    
  31.         492  bytes received via SQL*Net from client    
  32.           2  SQL*Net roundtrips to/from client    
  33.           0  sorts (memory)    
  34.           0  sorts (disk)    
  35.           2  rows processed   
SQL> select employee_id  
                  from employees c  
                 where c.first_name = 'Steven'   2    3  ;  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1445457117  
  
-------------------------------------------------------------------------------  
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
-------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |           |     1 |    11 |     3   (0)| 00:00:01 |  
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |    11 |     3   (0)| 00:00:01 |  
-------------------------------------------------------------------------------  
  
Predicate Information (identified by operation id):  
---------------------------------------------------  
  
   1 - filter("C"."FIRST_NAME"='Steven')  
  
  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
          8  consistent gets  
          0  physical reads  
          0  redo size  
        574  bytes sent via SQL*Net to client  
        492  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
          2  rows processed 


The filter condition here is FIRST_NAME, but FIRST_NAME is not indexed, so filter is used to mark it.
3. Statistics
Here's the main point. If you're tired, you can have a drink.O(8745;) O~
AUTOTRACE Statistics Column Interpretation
Sequence Number Column Name explain
1 recursive calls Recursive Survey
2 db block gets Number of block s read from buffer cache
3 consistent gets Number of block s of undo data read from buffer cache
4 physical reads Number of block s read from disk
5 redo size Size of redo generated by DML
6 sorts (memory) Sort amount executed in memory
7 sorts (disk) The amount of sorting performed on disk


1. recursive calls
The official website interprets recursive calls as follows:

       Recursive Calls:   Number of recursive calls generated at both the user and system level.   

       Oracle Database maintains tables used for internal processing. When it needs to change these tables, Oracle Database generates an internal SQL statement, which in turn generates a recursive call.In short, recursive calls are basically SQL performed on behalf of your SQL. So, if you had to parse the query, for example, you might have had to run some other queries to get data dictionary information. These would be recursive calls. Space management, security checks, calling PL/SQL from SQL—all incur recursive SQL calls.
There is also an explanation above IBM that you would like to see
       http://publib.boulder.ibm.com/tividd/td/ITMD/SC23-4724-00/en_US/HTML/oraclepac510rg59.htm
Summarize:
When one SQL statement is executed, calls are made to other SQL statements, which are called''recursive calls''or''recursive SQL statements''.
In that IBM document, there are six situations that trigger Recursive Call:

Such as:

(1) When we make an insert, there is not enough space to save the row record, and Oracle allocates space dynamically through Recursive Call.

(2) When executing a DDL statement, ORACLE always implicitly issues some recursive SQL statements to modify the data dictionary information for successful execution of the DDL statement.

(3) Recursive calls occur when the Shared Pool is too small and the data dictionary cache is too small to store ORACLE's system data dictionary information. These Recursive calls read the data dictionary information from the hard disk into memory.

(4) recursive SQL is also generated if there are SQL calls within stored procedures and triggers.
In these cases, mainly queries to the data dictionary, usually occur at the first execution and the second execution can generally be significantly reduced.Recursion consumes a lot of resources and can be problematic if the operation is complex!
Now let's give an example:
[sql] view plaincopy
  1. SQL> select * from employees;    
  2.     
  3. 107 rows selected.    
  4.     
  5.     
  6. Execution Plan    
  7. ----------------------------------------------------------    
  8. Plan hash value: 1445457117    
  9.     
  10. -------------------------------------------------------------------------------    
  11. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |    
  12. -------------------------------------------------------------------------------    
  13. |   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |    
  14. |   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |    
  15. -------------------------------------------------------------------------------    
  16.     
  17.     
  18. Statistics    
  19. ----------------------------------------------------------    
  20.           1  recursive calls    
  21.           0  db block gets    
  22.          15  consistent gets    
  23.           0  physical reads    
  24.           0  redo size    
  25.        9997  bytes sent via SQL*Net to client    
  26.         569  bytes received via SQL*Net from client    
  27.           9  SQL*Net roundtrips to/from client    
  28.           0  sorts (memory)    
  29.           0  sorts (disk)    
  30.         107  rows processed    
SQL> select * from employees;  
  
107 rows selected.  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1445457117  
  
-------------------------------------------------------------------------------  
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
-------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |  
-------------------------------------------------------------------------------  
  
  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
         15  consistent gets  
          0  physical reads  
          0  redo size  
       9997  bytes sent via SQL*Net to client  
        569  bytes received via SQL*Net from client  
          9  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
        107  rows processed  

  

Let's do it again
[sql] view plaincopy
  1. SQL> select * from employees;    
  2.     
  3. 107 rows selected.    
  4.     
  5.     
  6. Execution Plan    
  7. ----------------------------------------------------------    
  8. Plan hash value: 1445457117    
  9.     
  10. -------------------------------------------------------------------------------    
  11. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |    
  12. -------------------------------------------------------------------------------    
  13. |   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |    
  14. |   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |    
  15. -------------------------------------------------------------------------------    
  16.     
  17.     
  18. Statistics    
  19. ----------------------------------------------------------    
  20.           0  recursive calls    
  21.           0  db block gets    
  22.          15  consistent gets    
  23.           0  physical reads    
  24.           0  redo size    
  25.        9997  bytes sent via SQL*Net to client    
  26.         569  bytes received via SQL*Net from client    
  27.           9  SQL*Net roundtrips to/from client    
  28.           0  sorts (memory)    
  29.           0  sorts (disk)    
  30.         107  rows processed   
SQL> select * from employees;  
  
107 rows selected.  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1445457117  
  
-------------------------------------------------------------------------------  
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
-------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |  
-------------------------------------------------------------------------------  
  
  
Statistics  
----------------------------------------------------------  
          0  recursive calls  
          0  db block gets  
         15  consistent gets  
          0  physical reads  
          0  redo size  
       9997  bytes sent via SQL*Net to client  
        569  bytes received via SQL*Net from client  
          9  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
        107  rows processed 

  

The first query for employees yields a recursive call, and the second query yields a recursive call less often than the first because the information from the data dictionary is already in the cache, so the second recursive call is 0.
The others can be seen literally, so there is no need to explain them.

Keywords: SQL Oracle Database less

Added by Peredy on Fri, 24 May 2019 20:12:45 +0300