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
I like SET AUTOTRACE TRACEONLY, and our future examples are based on this approach
view plaincopy
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
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
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
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
Let's do it again
[sql] view plaincopy
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.
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
- 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
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
- 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
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
- 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
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
- 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
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
- 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
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.