Oracle Database: SQL Tuning Guide 12c Release 1 (12.1)
Oracle Database: SQL Tuning Guide 12c Release 1 (12.1)
Oracle Database: SQL Tuning Guide 12c Release 1 (12.1)
November 2015
Oracle Database SQL Tuning Guide, 12c Release 1 (12.1)
E49106-09
Copyright © 2013, 2015, Oracle and/or its affiliates. All rights reserved.
Contributors: Pete Belknap, Ali Cakmak, Sunil Chakkappen, Immanuel Chan, Deba Chatterjee, Chris
Chiappa, Dinesh Das, Leonidas Galanis, William Endress, Bruce Golbus, Katsumi Inoue, Kevin Jernigan,
Shantanu Joshi, Adam Kociubes, Allison Lee, Sue Lee, David McDermid, Colin McGregor, Ted Persky,
Ekrem Soylemez, Hong Su, Murali Thiyagarajah, Mark Townsend, Randy Urbano, Bharath Venkatakrishnan,
Hailing Yu
This software and related documentation are provided under a license agreement containing restrictions on
use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your
license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license,
transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse
engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is
prohibited.
The information contained herein is subject to change without notice and is not warranted to be error-free. If
you find any errors, please report them to us in writing.
If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it on
behalf of the U.S. Government, the following notice is applicable:
U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software,
any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are
"commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-
specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the
programs, including any operating system, integrated software, any programs installed on the hardware,
and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.
No other rights are granted to the U.S. Government.
This software or hardware is developed for general use in a variety of information management applications.
It is not developed or intended for use in any inherently dangerous applications, including applications that
may create a risk of personal injury. If you use this software or hardware in dangerous applications, then you
shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure its
safe use. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of this
software or hardware in dangerous applications.
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.
Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are
used under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron,
the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced Micro
Devices. UNIX is a registered trademark of The Open Group.
This software or hardware and documentation may provide access to or information about content, products,
and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly
disclaim all warranties of any kind with respect to third-party content, products, and services unless
otherwise set forth in an applicable agreement between you and Oracle. Oracle Corporation and its affiliates
will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party
content, products, or services, except as set forth in an applicable agreement between you and Oracle.
Contents
Preface ............................................................................................................................................................... xv
Audience ...................................................................................................................................................... xv
Related Documents..................................................................................................................................... xv
Conventions................................................................................................................................................ xvi
Changes in This Release for Oracle Database SQL Tuning Guide ................................... xvii
Changes in Oracle Database 12c Release 1 (12.1.0.2) ........................................................................... xvii
New Features .................................................................................................................................... xvii
Changes in Oracle Database 12c Release 1 (12.1.0.1) ........................................................................... xvii
New Features ................................................................................................................................... xviii
Deprecated Features.......................................................................................................................... xxi
Desupported Features ...................................................................................................................... xxi
Other Changes ................................................................................................................................... xxi
iii
Guidelines for Application Rollout ............................................................................................... 2-4
3 SQL Processing
About SQL Processing ............................................................................................................................. 3-1
SQL Parsing....................................................................................................................................... 3-2
SQL Optimization............................................................................................................................. 3-5
SQL Row Source Generation .......................................................................................................... 3-5
SQL Execution................................................................................................................................... 3-7
How Oracle Database Processes DML .................................................................................................. 3-8
How Row Sets Are Fetched ............................................................................................................ 3-8
Read Consistency ............................................................................................................................. 3-9
Data Changes .................................................................................................................................... 3-9
How Oracle Database Processes DDL ................................................................................................... 3-9
5 Query Transformations
OR Expansion............................................................................................................................................ 5-1
View Merging............................................................................................................................................ 5-2
Query Blocks in View Merging ...................................................................................................... 5-3
Simple View Merging ...................................................................................................................... 5-3
Complex View Merging .................................................................................................................. 5-6
Predicate Pushing ..................................................................................................................................... 5-8
Subquery Unnesting................................................................................................................................. 5-9
Query Rewrite with Materialized Views .............................................................................................. 5-9
Star Transformation................................................................................................................................ 5-10
About Star Schemas ....................................................................................................................... 5-11
Purpose of Star Transformations ................................................................................................. 5-11
iv
How Star Transformation Works................................................................................................. 5-11
Controls for Star Transformation................................................................................................. 5-12
Star Transformation: Scenario ...................................................................................................... 5-12
Temporary Table Transformation: Scenario............................................................................... 5-15
In-Memory Aggregation........................................................................................................................ 5-16
Purpose of In-Memory Aggregation ........................................................................................... 5-17
How In-Memory Aggregation Works......................................................................................... 5-17
Controls for In-Memory Aggregation ......................................................................................... 5-20
In-Memory Aggregation: Scenario .............................................................................................. 5-21
In-Memory Aggregation: Example.............................................................................................. 5-26
Table Expansion ...................................................................................................................................... 5-28
Purpose of Table Expansion ......................................................................................................... 5-28
How Table Expansion Works ....................................................................................................... 5-28
Table Expansion: Scenario ............................................................................................................ 5-29
Table Expansion and Star Transformation: Scenario ................................................................ 5-32
Join Factorization .................................................................................................................................... 5-33
Purpose of Join Factorization........................................................................................................ 5-34
How Join Factorization Works ..................................................................................................... 5-34
Factorization and Join Orders: Scenario...................................................................................... 5-35
Factorization of Outer Joins: Scenario ......................................................................................... 5-36
v
Reading Adaptive Plans .................................................................................................................. 7-2
Viewing Parallel Execution with EXPLAIN PLAN..................................................................... 7-6
Viewing Bitmap Indexes with EXPLAIN PLAN ......................................................................... 7-8
Viewing Result Cache with EXPLAIN PLAN.............................................................................. 7-9
Viewing Partitioned Objects with EXPLAIN PLAN ................................................................... 7-9
PLAN_TABLE Columns................................................................................................................ 7-16
Execution Plan Reference ...................................................................................................................... 7-28
Execution Plan Views .................................................................................................................... 7-28
PLAN_TABLE Columns................................................................................................................ 7-29
DBMS_XPLAN Program Units .................................................................................................... 7-40
9 Joins
About Joins ................................................................................................................................................ 9-1
Join Trees ........................................................................................................................................... 9-1
How the Optimizer Executes Join Statements ............................................................................. 9-3
vi
How the Optimizer Chooses Execution Plans for Joins ............................................................. 9-3
Join Methods.............................................................................................................................................. 9-5
Nested Loops Joins........................................................................................................................... 9-5
Hash Joins........................................................................................................................................ 9-15
Sort Merge Joins.............................................................................................................................. 9-18
Cartesian Joins ................................................................................................................................ 9-21
Join Types................................................................................................................................................. 9-23
Inner Joins........................................................................................................................................ 9-23
Outer Joins....................................................................................................................................... 9-25
Semijoins.......................................................................................................................................... 9-29
Antijoins........................................................................................................................................... 9-31
Join Optimizations .................................................................................................................................. 9-35
Bloom Filters ................................................................................................................................... 9-36
Partition-Wise Joins........................................................................................................................ 9-39
11 Histograms
Purpose of Histograms .......................................................................................................................... 11-1
When Oracle Database Creates Histograms ....................................................................................... 11-2
How Oracle Database Chooses the Histogram Type ........................................................................ 11-3
Cardinality Algorithms When Using Histograms ............................................................................. 11-4
Endpoint Numbers and Values.................................................................................................... 11-4
Popular and Nonpopular Values ................................................................................................. 11-4
vii
Bucket Compression ...................................................................................................................... 11-5
Frequency Histograms ........................................................................................................................... 11-6
Criteria For Frequency Histograms ............................................................................................. 11-6
Generating a Frequency Histogram ............................................................................................ 11-6
Top Frequency Histograms ................................................................................................................. 11-10
Criteria For Top Frequency Histograms ................................................................................... 11-10
Generating a Top Frequency Histogram .................................................................................. 11-11
Height-Balanced Histograms (Legacy).............................................................................................. 11-14
Criteria for Height-Balanced Histograms................................................................................. 11-14
Generating a Height-Balanced Histogram ............................................................................... 11-14
Hybrid Histograms............................................................................................................................... 11-18
How Endpoint Repeat Counts Work ........................................................................................ 11-18
Criteria for Hybrid Histograms.................................................................................................. 11-20
Generating a Hybrid Histogram ................................................................................................ 11-20
viii
13 Managing Optimizer Statistics: Advanced Topics
Controlling Dynamic Statistics ............................................................................................................. 13-1
About Dynamic Statistics Levels.................................................................................................. 13-2
Setting Dynamic Statistics Levels Manually .............................................................................. 13-3
Disabling Dynamic Statistics ........................................................................................................ 13-5
Publishing Pending Optimizer Statistics............................................................................................. 13-5
About Pending Optimizer Statistics ............................................................................................ 13-5
User Interfaces for Publishing Optimizer Statistics .................................................................. 13-7
Managing Published and Pending Statistics .............................................................................. 13-8
Managing Extended Statistics............................................................................................................. 13-11
Managing Column Group Statistics .......................................................................................... 13-11
Managing Expression Statistics.................................................................................................. 13-21
Locking and Unlocking Optimizer Statistics .................................................................................... 13-25
Locking Statistics .......................................................................................................................... 13-26
Unlocking Statistics...................................................................................................................... 13-26
Restoring Optimizer Statistics............................................................................................................. 13-27
About Restore Operations for Optimizer Statistics................................................................. 13-27
Guidelines for Restoring Optimizer Statistics.......................................................................... 13-28
Restrictions for Restoring Optimizer Statistics ........................................................................ 13-28
Restoring Optimizer Statistics Using DBMS_STATS .............................................................. 13-29
Managing Optimizer Statistics Retention ......................................................................................... 13-30
Obtaining Optimizer Statistics History..................................................................................... 13-30
Changing the Optimizer Statistics Retention Period .............................................................. 13-31
Purging Optimizer Statistics....................................................................................................... 13-32
Importing and Exporting Optimizer Statistics ................................................................................. 13-33
About Transporting Optimizer Statistics.................................................................................. 13-33
Transporting Optimizer Statistics to a Test Database............................................................. 13-34
Running Statistics Gathering Functions in Reporting Mode ......................................................... 13-36
Reporting on Past Statistics Gathering Operations ......................................................................... 13-38
Managing SQL Plan Directives........................................................................................................... 13-40
ix
Guidelines for Join Order Hints ................................................................................................. 14-13
x
User Interfaces for SQL Test Case Builder .......................................................................................... 17-4
Graphical Interface for SQL Test Case Builder .......................................................................... 17-4
Command-Line Interface for SQL Test Case Builder................................................................ 17-5
Running SQL Test Case Builder ........................................................................................................... 17-5
xi
Loading a SQL Tuning Set..................................................................................................................... 19-6
Displaying the Contents of a SQL Tuning Set .................................................................................... 19-8
Modifying a SQL Tuning Set............................................................................................................... 19-10
Transporting a SQL Tuning Set .......................................................................................................... 19-11
About Transporting SQL Tuning Sets....................................................................................... 19-11
Transporting SQL Tuning Sets with DBMS_SQLTUNE ........................................................ 19-12
Dropping a SQL Tuning Set ................................................................................................................ 19-14
xii
Terminating SQL Access Advisor Task Execution.................................................................. 21-24
Deleting SQL Access Advisor Tasks.......................................................................................... 21-26
Marking SQL Access Advisor Recommendations................................................................... 21-27
Modifying SQL Access Advisor Recommendations ............................................................... 21-28
SQL Access Advisor Examples ........................................................................................................... 21-29
SQL Access Advisor Reference........................................................................................................... 21-29
Action Attributes in the DBA_ADVISOR_ACTIONS View .................................................. 21-29
Categories for SQL Access Advisor Task Parameters............................................................. 21-31
SQL Access Advisor Constants .................................................................................................. 21-32
xiii
Evolving SQL Plan Baselines Manually ............................................................................................ 23-27
About the DBMS_SPM Evolve Functions................................................................................. 23-28
Managing an Evolve Task ........................................................................................................... 23-29
Dropping SQL Plan Baselines ............................................................................................................. 23-37
Managing the SQL Management Base............................................................................................... 23-39
Changing the Disk Space Limit for the SMB ............................................................................ 23-39
Changing the Plan Retention Policy in the SMB...................................................................... 23-40
Glossary
Index
xiv
Preface
• Audience
• Related Documents
• Conventions
Audience
This document is intended for database administrators and application developers
who perform the following tasks:
Related Documents
This manual assumes that you are familiar with the following documents:
xv
To learn how to tune data warehouse environments, see Oracle Database Data
Warehousing Guide.
Many examples in this book use the sample schemas, which are installed by default
when you select the Basic Installation option with an Oracle Database. See Oracle
Database Sample Schemas for information on how these schemas were created and how
you can use them.
To learn about Oracle Database error messages, see Oracle Database Error Messages
Reference. Oracle Database error message documentation is only available in HTML. If
you are accessing the error message documentation on the Oracle Documentation CD,
then you can browse the error messages by range. After you find the specific range,
use your browser's find feature to locate the specific message. When connected to the
Internet, you can search for a specific error message using the error message search
feature of the Oracle online documentation.
Conventions
The following text conventions are used in this document:
Convention Meaning
boldface Boldface type indicates graphical user interface elements associated
with an action, or terms defined in text or the glossary.
italic Italic type indicates book titles, emphasis, or placeholder variables for
which you supply particular values.
xvi
Changes in This Release for Oracle
Database SQL Tuning Guide
New Features
The following features are new in this release:
• In-memory aggregation
This optimization minimizes the join and GROUP BY processing required for each
row when joining a single large table to multiple small tables, as in a star schema.
VECTOR GROUP BY aggregation uses the infrastructure related to parallel query
(PQ) processing, and blends it with CPU-efficient algorithms to maximize the
performance and effectiveness of the initial aggregation performed before
redistributing fact data.
See “In-Memory Aggregation”.
– Indicates whether a plan is adaptive, and show its current status: resolving or
resolved.
– Provides a list that enables you to select the current, full, or final plans
See “Adaptive Plans” to learn more about adaptive plans, and “Reporting on
Database Operations Using SQL Monitor” to learn more about SQL Monitor.
xvii
New Features
The following features are new in this release:
– Adaptive plans
An adaptive plan has built-in options that enable the final plan for a statement
to differ from the default plan. During the first execution, before a specific
subplan becomes active, the optimizer makes a final decision about which
option to use. The optimizer bases its choice on observations made during the
execution up to this point. The ability of the optimizer to adapt plans can
improve query performance.
See “Adaptive Plans”.
– Automatic reoptimization
When using automatic reoptimization, the optimizer monitors the initial
execution of a query. If the actual execution statistics vary significantly from the
original plan statistics, then the optimizer records the execution statistics and
uses them to choose a better plan the next time the statement executes. The
database uses information obtained during automatic reoptimization to
generate SQL plan directives automatically.
See “Automatic Reoptimization”.
xviii
In releases earlier than Oracle Database 12c, Oracle Database only used dynamic
statistics (previously called dynamic sampling) when one or more of the tables in
a query did not have optimizer statistics. Starting in this release, the optimizer
automatically decides whether dynamic statistics are useful and which dynamic
statistics level to use for all SQL statements. Dynamic statistics gathers are
persistent and usable by other queries.
See “Dynamic Statistics”.
xix
You can use DBMS_STATS functions to report on a specific statistics gathering
operation or on operations that occurred during a specified time.
See “Reporting on Past Statistics Gathering Operations”.
xx
• Automatic updates of global statistics for tables with stale or locked partition
statistics
Incremental statistics can automatically calculate global statistics for a partitioned
table even if the partition or subpartition statistics are stale and locked.
See “Maintaining Incremental Statistics for Tables with Stale or Locked Partition
Statistics”.
Deprecated Features
The following features are deprecated in this release, and may be desupported in a
future release:
• Stored outlines
See Managing SQL Plan Baselines for information about alternatives.
Desupported Features
Some features previously described in this document are desupported in Oracle
Database 12c. See Oracle Database Upgrade Guide for a list of desupported features.
Other Changes
The following are additional changes in the release:
– Oracle Database Performance Tuning Guide, which contains only topics that
pertain to tuning the database
– Oracle Database SQL Tuning Guide, which contains only topics that pertain to
tuning SQL
xxi
Part I
SQL Performance Fundamentals
See Also:
• Reduce user response time, which means decreasing the time between when a user
issues a statement and receives a response
• Improve throughput, which means using the least amount of resources necessary
to process all rows accessed by a statement
For a response time problem, consider an online book seller application that hangs for
three minutes after a customer updates the shopping cart. Contrast with a three-
minute parallel query in a data warehouse that consumes all of the database host
CPU, preventing other queries from running. In each case, the user response time is
three minutes, but the cause of the problem is different, and so is the tuning goal.
The optimizer statistics are crucial to SQL tuning. If these statistics do not exist or
are no longer accurate, then the optimizer cannot generate the best plan. Other
data relevant to SQL performance include the structure of tables and views that
the statement accessed, and definitions of any indexes available to the statement.
• Hardware problems
Suboptimal performance might be connected with memory, I/O, and CPU
problems.
shared pool size fixes the problem at the database level and improves
performance for all sessions. However, if a single SQL statement is not using a
helpful index, then changing the optimizer initialization parameters for the entire
database could harm overall performance. If a single SQL statement has a
problem, then an appropriately scoped solution addresses just this problem with
this statement.
See Also:
See Also:
“About SQL Tuning Sets”
See Also:
See Also:
See Also:
See Also:
See Also:
Oracle Database Testing Guide
Execution Plans
Execution plans are the principal diagnostic tool in manual SQL tuning. For example,
you can view plans to determine whether the optimizer selects the plan you expect, or
identify the effect of creating an index on a table.
You can display execution plans in multiple ways. The following tools are the most
commonly used:
• EXPLAIN PLAN
This SQL statement enables you to view the execution plan that the optimizer
would use to execute a SQL statement without actually executing the statement.
See Oracle Database SQL Language Reference.
• AUTOTRACE
The AUTOTRACE command in SQL*Plus generates the execution plan and statistics
about the performance of a query. This command provides statistics such as disk
reads and memory reads. See SQL*Plus User's Guide and Reference.
• V$ACTIVE_SESSION_HISTORY
• V$SESSION
• V$SESSION_LONGOPS
• V$SQL
• V$SQL_PLAN
See Also:
Application Tracing
A SQL trace file provides performance information on individual SQL statements:
parse counts, physical and logical reads, misses on the library cache, and so on. You
can use this information to diagnose SQL performance problems.
You can enable and disable SQL tracing for a specific session using the
DBMS_MONITOR or DBMS_SESSION packages. Oracle Database implements tracing by
generating a trace file for each server process when you enable the tracing mechanism.
Oracle Database provides the following command-line tools for analyzing trace files:
• TKPROF
This utility accepts as input a trace file produced by the SQL Trace facility, and
then produces a formatted output file.
• trcsess
This utility consolidates trace output from multiple trace files based on criteria such
as session ID, client ID, and service ID. After trcsess merges the trace
information into a single output file, you can format the output file with TKPROF.
trcsess is useful for consolidating the tracing of a particular session for
performance or debugging purposes.
End-to-End Application Tracing simplifies the process of diagnosing performance
problems in multitier environments. In these environments, the middle tier routes a
request from an end client to different database sessions, making it difficult to track a
client across database sessions. End-to-End application tracing uses a client ID to
uniquely trace a specific end-client through all tiers to the database.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_MONITOR and DBMS_SESSION
Optimizer Hints
A hint is an instruction passed to the optimizer through comments in a SQL
statement. Hints enable you to make decisions normally made automatically by the
optimizer.
In a test or development environment, hints are useful for testing the performance of a
specific access path. For example, you may know that a specific index is more selective
for certain queries. In this case, you may use hints to instruct the optimizer to use a
better execution plan, as in the following example:
SELECT /*+ INDEX (employees emp_department_ix) */
employee_id, department_id
FROM employees
WHERE department_id > 50;
See Also:
This chapter describes the recommended methodology for SQL tuning. This chapter
contains the following topics:
– Hard parsing
A SQL statement is submitted for the first time, and no match is found in the
shared pool. Hard parses are the most resource-intensive and unscalable,
because they perform all the operations involved in a parse.
– Soft parsing
A SQL statement is submitted for the first time, and a match is found in the
shared pool. The match can be the result of previous execution by another user.
The SQL statement is shared, which is optimal for performance. However, soft
parses are not ideal, because they still require syntax and security checking,
which consume system resources.
Because parsing should be minimized as much as possible, application developers
should design their applications to parse SQL statements once and execute them
many times. This is done through cursors. Experienced SQL programmers should
be familiar with the concept of opening and re-executing cursors.
The following example shows the results of some tests on a simple OLTP
application:
Test #Users Supported
No Parsing all statements 270
Soft Parsing all statements 150
Hard Parsing all statements 60
Re-Connecting for each Transaction 30
• Use the Automatic Database Diagnostic Monitor (ADDM) and SQL Tuning
Advisor for design validation.
the steady state condition. Likewise, after a benchmark run, a ramp-down period is
useful so that the system frees resources, and users cease work and disconnect.
• Big Bang approach - all users migrate to the new system at once
• Trickle approach - users slowly migrate from existing systems to the new one
Both approaches have merits and disadvantages. The Big Bang approach relies on
reliable testing of the application at the required scale, but has the advantage of
minimal data conversion and synchronization with the old system, because it is
simply switched off. The Trickle approach allows debugging of scalability issues as the
workload increases, but might mean that data must be migrated to and from legacy
systems as the transition takes place.
It is difficult to recommend one approach over the other, because each technique has
associated risks that could lead to system outages as the transition takes place.
Certainly, the Trickle approach allows profiling of real users as they are introduced to
the new application, and allows the system to be reconfigured while only affecting the
migrated users. This approach affects the work of the early adopters, but limits the
load on support services. Thus, unscheduled outages only affect a small percentage of
the user population.
The decision on how to roll out a new application is specific to each business. Any
adopted approach has its own unique pressures and stresses. The more testing and
knowledge that you derive from the testing process, the more you realize what is best
for the rollout.
• SQL Processing
• Query Transformations
3
SQL Processing
This chapter explains how Oracle Database processes SQL statements. Specifically, the
section explains the way in which the database processes DDL statements to create
objects, DML to modify data, and queries to retrieve data.
This chapter contains the following topics:
SQL Statement
Parsing
Syntax
Check
Semantic
Check
Hard Parse
Generation of
multiple Optimization
execution plans
Execution
SQL Parsing
The first stage of SQL processing is parsing. This stage involves separating the pieces
of a SQL statement into a data structure that other routines can process. The database
parses a statement when instructed by the application, which means that only the
application, and not the database itself, can reduce the number of parses.
When an application issues a SQL statement, the application makes a parse call to the
database to prepare the statement for execution. The parse call opens or creates a
cursor, which is a handle for the session-specific private SQL area that holds a parsed
SQL statement and other processing information. The cursor and private SQL area are
in the program global area (PGA).
During the parse call, the database performs the following checks:
• Syntax Check
• Semantic Check
The preceding checks identify the errors that can be found before statement execution.
Some errors cannot be caught by parsing. For example, the database can encounter
deadlocks or errors in data conversion only during statement execution.
See Also:
Oracle Database Concepts to learn about deadlocks
Syntax Check
Oracle Database must check each SQL statement for syntactic validity. A statement
that breaks a rule for well-formed SQL syntax fails the check. For example, the
following statement fails because the keyword FROM is misspelled as FORM:
SQL> SELECT * FORM employees;
SELECT * FORM employees
*
ERROR at line 1:
ORA-00923: FROM keyword not found where expected
Semantic Check
The semantics of a statement are its meaning. Thus, a semantic check determines
whether a statement is meaningful, for example, whether the objects and columns in
the statement exist. A syntactically correct statement can fail a semantic check, as
shown in the following example of a query of a nonexistent table:
SQL> SELECT * FROM nonexistent_table;
SELECT * FROM nonexistent_table
*
ERROR at line 1:
ORA-00942: table or view does not exist
• Hard parse
If Oracle Database cannot reuse existing code, then it must build a new executable
version of the application code. This operation is known as a hard parse, or a
library cache miss.
Note:
The database always perform a hard parse of DDL.
During the hard parse, the database accesses the library cache and data dictionary
cache numerous times to check the data dictionary. When the database accesses
these areas, it uses a serialization device called a latch on required objects so that
their definition does not change. Latch contention increases statement execution
time and decreases concurrency.
• Soft parse
A soft parse is any parse that is not a hard parse. If the submitted statement is the
same as a reusable SQL statement in the shared pool, then Oracle Database reuses
the existing code. This reuse of code is also called a library cache hit.
Soft parses can vary in how much work they perform. For example, configuring the
session shared SQL area can sometimes reduce the amount of latching in the soft
parses, making them "softer."
In general, a soft parse is preferable to a hard parse because the database skips the
optimization and row source generation steps, proceeding straight to execution.
Figure 3-2 is a simplified representation of a shared pool check of an UPDATE
statement in a dedicated server architecture.
Shared Pool
Library Cache
Shared SQL Area Private
3667723989 SQL Area
3967354608
2190280494
User
Private SQL Area
If a check determines that a statement in the shared pool has the same hash value, then
the database performs semantic and environment checks to determine whether the
statements have the same meaning. Identical syntax is not sufficient. For example,
suppose two different users log in to the database and issue the following SQL
statements:
CREATE TABLE my_table ( some_col INTEGER );
SELECT * FROM my_table;
The SELECT statements for the two users are syntactically identical, but two separate
schema objects are named my_table. This semantic difference means that the second
statement cannot reuse the code for the first statement.
Even if two statements are semantically identical, an environmental difference can
force a hard parse. In this context, the optimizer environment is the totality of session
settings that can affect execution plan generation, such as the work area size or
optimizer settings (for example, the optimizer mode). Consider the following series of
SQL statements executed by a single user:
ALTER SESSION SET OPTIMIZER_MODE=ALL_ROWS;
ALTER SYSTEM FLUSH SHARED_POOL; # optimizer environment 1
SELECT * FROM sh.sales;
In the preceding example, the same SELECT statement is executed in three different
optimizer environments. Consequently, the database creates three separate shared
SQL areas for these statements and forces a hard parse of each statement.
See Also:
• Oracle Database Concepts to learn about private SQL areas and shared SQL
areas
SQL Optimization
During the optimization stage, Oracle Database must perform a hard parse at least
once for every unique DML statement and performs the optimization during this
parse. The database never optimizes DDL unless it includes a DML component such
as a subquery that requires optimization. Query Optimizer Concepts explains the
optimization process in more detail.
database. The iterative plan is a binary program that, when executed by the SQL
engine, produces the result set.
The execution plan takes the form of a combination of steps. Each step returns a row
set. The next step either uses the rows in this set, or the last step returns the rows to
the application issuing the SQL statement.
A row source is a row set returned by a step in the execution plan along with a control
structure that can iteratively process the rows. The row source can be a table, view, or
result of a join or grouping operation.
The row source generator produces a row source tree, which is a collection of row
sources. The row source tree shows the following information:
Execution Plan
----------------------------------------------------------
Plan hash value: 975837011
--------------------------------------------------------------------------------
| Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 189 | 7(15)| 00:00:01 |
|*1 | HASH JOIN | | 3 | 189 | 7(15)| 00:00:01 |
|*2 | HASH JOIN | | 3 | 141 | 5(20)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 3 | 60 | 2 (0)| 00:00:01 |
|*4 | INDEX RANGE SCAN | EMP_NAME_IX | 3 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL | JOBS | 19 | 513 | 2 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------
1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
2 - access("E"."JOB_ID"="J"."JOB_ID")
4 - access("E"."LAST_NAME" LIKE 'A%')
filter("E"."LAST_NAME" LIKE 'A%')
SQL Execution
During execution, the SQL engine executes each row source in the tree produced by
the row source generator. This step is the only mandatory step in DML processing.
Figure 3-3 is an execution tree, also called a parse tree, that shows the flow of row
sources from one step to another in the plan in Example 3-1. In general, the order of
the steps in execution is the reverse of the order in the plan, so you read the plan from
the bottom up.
Each step in an execution plan has an ID number. The numbers in Figure 3-3
correspond to the Id column in the plan shown in Example 3-1. Initial spaces in the
Operation column of the plan indicate hierarchical relationships. For example, if the
name of an operation is preceded by two spaces, then this operation is a child of an
operation preceded by one space. Operations preceded by one space are children of
the SELECT statement itself.
1
HASH JOIN
2 6
HASH JOIN TABLE ACCESS
FULL
departments
3 5
TABLE ACCESS TABLE ACCESS
BY INDEX ROWID FULL
employees jobs
4
INDEX RANGE
SCAN
emp_name_ix
In Figure 3-3, each node of the tree acts as a row source, which means that each step of
the execution plan in Example 3-1 either retrieves rows from the database or accepts
rows from one or more row sources as input. The SQL engine executes each row
source as follows:
• Steps indicated by the black boxes physically retrieve data from an object in the
database. These steps are the access paths, or techniques for retrieving data from
the database.
– Step 6 uses a full table scan to retrieve all rows from the departments table.
– Step 5 uses a full table scan to retrieve all rows from the jobs table.
– Step 4 scans the emp_name_ix index in order, looking for each key that begins
with the letter A and retrieving the corresponding rowid. For example, the
rowid corresponding to Atkinson is AAAPzRAAFAAAABSAAe.
– Step 3 retrieves from the employees table the rows whose rowids were
returned by Step 4. For example, the database uses rowid
AAAPzRAAFAAAABSAAe to retrieve the row for Atkinson.
– Step 2 performs a hash join, accepting row sources from Steps 3 and 5, joining
each row from the Step 5 row source to its corresponding row in Step 3, and
returning the resulting rows to Step 1.
For example, the row for employee Atkinson is associated with the job name
Stock Clerk.
– Step 1 performs another hash join, accepting row sources from Steps 2 and 6,
joining each row from the Step 6 source to its corresponding row in Step 2, and
returning the result to the client.
For example, the row for employee Atkinson is associated with the
department named Shipping.
In some execution plans the steps are iterative and in others sequential. The hash join
shown in Example 3-1 is sequential. The database completes the steps in their entirety
based on the join order. The database starts with the index range scan of
emp_name_ix. Using the rowids that it retrieves from the index, the database reads
the matching rows in the employees table, and then scans the jobs table. After it
retrieves the rows from the jobs table, the database performs the hash join.
During execution, the database reads the data from disk into memory if the data is not
in memory. The database also takes out any locks and latches necessary to ensure data
integrity and logs any changes made during the SQL execution. The final stage of
processing a SQL statement is closing the cursor.
performs. For some queries the database returns the first row as quickly as possible,
whereas for others it creates the entire result set before returning the first row.
Read Consistency
In general, a query retrieves data by using the Oracle Database read consistency
mechanism. This mechanism, which uses undo data to show past versions of data,
guarantees that all data blocks read by a query are consistent to a single point in time.
For an example of read consistency, suppose a query must read 100 data blocks in a
full table scan. The query processes the first 10 blocks while DML in a different session
modifies block 75. When the first session reaches block 75, it realizes the change and
uses undo data to retrieve the old, unmodified version of the data and construct a
noncurrent version of block 75 in memory.
See Also:
Data Changes
DML statements that must change data use the read consistency mechanism to
retrieve only the data that matched the search criteria when the modification began.
Afterward, these statements retrieve the data blocks as they exist in their current state
and make the required modifications. The database must perform other actions related
to the modification of the data such as generating redo and undo data.
Typically, the database would run dozens of recursive statements to execute the
preceding statement. The recursive SQL would perform actions such as the following:
• Insert rows that define the table into the data dictionary
See Also:
This chapter describes the most important concepts relating to the query optimizer.
This chapter contains the following topics:
• Cost-Based Optimization
• Execution Plans
Cost-Based Optimization
Query optimization is the overall process of choosing the most efficient means of
executing a SQL statement. SQL is a nonprocedural language, so the optimizer is free
to merge, reorganize, and process in any order.
The database optimizes each SQL statement based on statistics collected about the
accessed data. When generating execution plans, the optimizer considers different
access paths and join methods. Factors considered by the optimizer include:
Note:
The optimizer may not make the same decisions from one version of Oracle
Database to the next. In recent versions, the optimizer might make different
decision because better information is available and more optimizer
transformations are possible.
Execution Plans
An execution plan describes a recommended method of execution for a SQL
statement. The plans shows the combination of the steps Oracle Database uses to
execute a SQL statement. Each step either retrieves rows of data physically from the
database or prepares them for the user issuing the statement.
An execution plan displays the cost of the entire plan, indicated on line 0, and each
separate operation. The cost is an internal unit that the execution plan only displays to
allow for plan comparisons. Thus, you cannot tune or change the cost value.
In Figure 4-1, the optimizer generates two possible execution plans for an input SQL
statement, uses statistics to estimate their costs, compares their costs, and then chooses
the plan with the lowest cost.
GB Plan GB Plan
1 2
NL HJ
NL HJ
Generates Multiple
Plans and
Compares Them
Statistics
1 0 1 1 0 0 1 0 0
Query Blocks
As shown in Figure 4-1, the input to the optimizer is a parsed representation of a SQL
statement. Each SELECT block in the original SQL statement is represented internally
by a query block. A query block can be a top-level statement, subquery, or unmerged
view (see “View Merging”).
Example 4-1 Query Blocks
The following SQL statement consists of two query blocks. The subquery in
parentheses is the inner query block. The outer query block, which is the rest of the
SQL statement, retrieves names of employees in the departments whose IDs were
supplied by the subquery. The query form determines how query blocks are
interrelated.
SELECT first_name, last_name
FROM hr.employees
WHERE department_id
IN (SELECT department_id
FROM hr.departments
WHERE location_id = 1800);
See Also:
Oracle Database Concepts for an overview of SQL processing
Query Subplans
For each query block, the optimizer generates a query subplan. The database
optimizes query blocks separately from the bottom up. Thus, the database optimizes
the innermost query block first and generates a subplan for it, and then generates the
outer query block representing the entire query.
The number of possible plans for a query block is proportional to the number of
objects in the FROM clause. This number rises exponentially with the number of
objects. For example, the possible plans for a join of five tables are significantly higher
than the possible plans for a join of two tables.
Query
Transformer
Transformed query
statistics Data
Estimator Dictionary
Query + estimates
Plan
Generator
Query Plan
(to Row Source Generator)
A set of query blocks represents a parsed query, which is the input to the optimizer.
The optimizer performs the following operations:
1. Query transformer
The optimizer determines whether it is helpful to change the form of the query so
that the optimizer can generate a better execution plan. See “Query Transformer”.
2. Estimator
The optimizer estimates the cost of each plan based on statistics in the data
dictionary. See “Estimator”.
3. Plan Generator
The optimizer compares the costs of plans and chooses the lowest-cost plan,
known as the execution plan, to pass to the row source generator. See “Plan
Generator”.
Query Transformer
For some statements, the query transformer determines whether it is advantageous to
rewrite the original SQL statement into a semantically equivalent SQL statement with
a lower cost. When a viable alternative exists, the database calculates the cost of the
alternatives separately and chooses the lowest-cost alternative. Query Transformations
describes the different types of optimizer transformations.
Figure 4-3 shows the query transformer rewriting an input query that uses OR into an
output query that uses UNION ALL.
SELECT *
FROM sales
WHERE promo_id=33
OR prod_id=136;
Query Transformer
SELECT *
FROM sales
WHERE prod_id=136
UNION ALL
SELECT *
FROM sales
WHERE promo_id=33
AND LNNVL(prod_id=136);
See Also:
Query Transformations
Estimator
The estimator is the component of the optimizer that determines the overall cost of a
given execution plan.
The estimator uses three different measures to determine cost:
• Selectivity
The percentage of rows in the row set that the query selects, with 0 meaning no
rows and 1 meaning all rows. Selectivity is tied to a query predicate, such as WHERE
last_name LIKE 'A%', or a combination of predicates. A predicate becomes
more selective as the selectivity value approaches 0 and less selective (or more
unselective) as the value approaches 1.
Note:
• Cardinality
The cardinality is the number of rows returned by each operation in an execution
plan. This input, which is crucial to obtaining an optimal plan, is common to all
cost functions. The estimator can derive cardinality from the table statistics
collected by DBMS_STATS, or derive it after accounting for effects from predicates
(filter, join, and so on), DISTINCT or GROUP BY operations, and so on. The Rows
column in an execution plan shows the estimated cardinality.
• Cost
This measure represents units of work or resource used. The query optimizer uses
disk I/O, CPU usage, and memory usage as units of work.
As shown in Figure 4-4, if statistics are available, then the estimator uses them to
compute the measures. The statistics improve the degree of accuracy of the measures.
GB Plan
Estimator
HJ
HJ Total Cost
Statistics
1 0 1 0 0
0 0 0 1 1
0 1 1 0 1
For the query shown in Example 4-1, the estimator uses selectivity, estimated
cardinality (a total return of 10 rows), and cost measures to produce its total cost
estimate of 3:
--------------------------------------------------------------------------------
| Id| Operation |Name |Rows|Bytes|Cost %CPU|Time|
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10| 250| 3 (0)| 00:00:01|
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 10| 250| 3 (0)| 00:00:01|
|*3 | TABLE ACCESS FULL |DEPARTMENTS | 1| 7| 2 (0)| 00:00:01|
|*4 | INDEX RANGE SCAN |EMP_DEPARTMENT_IX| 10| | 0 (0)| 00:00:01|
| 5 | TABLE ACCESS BY INDEX ROWID|EMPLOYEES | 10| 180| 1 (0)| 00:00:01|
--------------------------------------------------------------------------------
Selectivity
The selectivity represents a fraction of rows from a row set. The row set can be a base
table, a view, or the result of a join. The selectivity is tied to a query predicate, such as
last_name = 'Smith', or a combination of predicates, such as last_name =
'Smith' AND job_id = 'SH_CLERK'.
Note:
A predicate filters a specific number of rows from a row set. Thus, the selectivity of a
predicate indicates how many rows pass the predicate test. Selectivity ranges from 0.0
to 1.0. A selectivity of 0.0 means that no rows are selected from a row set, whereas a
selectivity of 1.0 means that all rows are selected. A predicate becomes more selective
as the value approaches 0.0 and less selective (or more unselective) as the value
approaches 1.0.
The optimizer estimates selectivity depending on whether statistics are available:
• Statistics available
When statistics are available, the estimator uses them to estimate selectivity.
Assume there are 150 distinct employee last names. For an equality predicate
last_name = 'Smith', selectivity is the reciprocal of the number n of distinct
values of last_name, which in this example is .006 because the query selects rows
that contain 1 out of 150 distinct values.
If a histogram exists on the last_name column, then the estimator uses the
histogram instead of the number of distinct values. The histogram captures the
distribution of different values in a column, so it yields better selectivity estimates,
especially for columns that have data skew. See Histograms .
Cardinality
The cardinality is the number of rows returned by each operation in an execution
plan. For example, if the optimizer estimate for the number of rows returned by a full
table scan is 100, then the cardinality estimate for this operation is 100. The cardinality
estimate appears in the Rows column of the execution plan.
The optimizer determines the cardinality for each operation based on a complex set of
formulas that use both table and column level statistics, or dynamic statistics, as input.
The optimizer uses one of the simplest formulas when a single equality predicate
appears in a single-table query, with no histogram. In this case, the optimizer assumes
a uniform distribution and calculates the cardinality for the query by dividing the total
number of rows in the table by the number of distinct values in the column used in the
WHERE clause predicate.
The employees table contains 107 rows. The current database statistics indicate that
the number of distinct values in the salary column is 58. Thus, the optimizer
calculates the cardinality of the result set as 2, using the formula 107/58=1.84.
Cardinality estimates must be as accurate as possible because they influence all aspects
of the execution plan. Cardinality is important when the optimizer determines the cost
of a join. For example, in a nested loops join of the employees and departments
tables, the number of rows in employees determines how often the database must
probe the departments table. Cardinality is also important for determining the cost
of sorts.
Cost
The optimizer cost model accounts for the I/O, CPU, and network resources that a
query is predicted to use. The cost is an internal numeric measure that represents the
estimated resource usage for a plan. The lower the cost, the more efficient the plan.
The execution plan displays the cost of the entire plan, which is indicated on line 0,
and each individual operation. For example, the following plan shows a cost of 14.
EXPLAINED SQL STATEMENT:
------------------------
SELECT prod_category, AVG(amount_sold) FROM sales s, products p WHERE
p.prod_id = s.prod_id GROUP BY prod_category
----------------------------------------------------------------------
| Id | Operation | Name | Cost (%CPU)|
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 (100)|
| 1 | HASH GROUP BY | | 14 (22)|
| 2 | HASH JOIN | | 13 (16)|
| 3 | VIEW | index$_join$_002 | 7 (15)|
| 4 | HASH JOIN | | |
| 5 | INDEX FAST FULL SCAN| PRODUCTS_PK | 4 (0)|
| 6 | INDEX FAST FULL SCAN| PRODUCTS_PROD_CAT_IX | 4 (0)|
| 7 | PARTITION RANGE ALL | | 5 (0)|
| 8 | TABLE ACCESS FULL | SALES | 5 (0)|
----------------------------------------------------------------------
The cost is an internal unit that you can use for plan comparisons. You cannot tune or
change it.
The access path determines the number of units of work required to get data from a
base table. The access path can be a table scan, a fast full index scan, or an index scan.
• Index scan
The cost of an index scan depends on the levels in the B-tree, the number of index
leaf blocks to be scanned, and the number of rows to be fetched using the rowid in
the index keys. The cost of fetching rows using rowids depends on the index
clustering factor.
The join cost represents the combination of the individual access costs of the two row
sets being joined, plus the cost of the join operation.
Plan Generator
The plan generator explores various plans for a query block by trying out different
access paths, join methods, and join orders. Many plans are possible because of the
various combinations that the database can use to produce the same result. The
optimizer picks the plan with the lowest cost.
Figure 4-5 shows the optimizer testing different plans for an input query.
Optimizer
Transformer
Access Path
Index
Full Table Scan
Hash Join
departments 0, employees 1
The following snippet from an optimizer trace file shows some computations that the
optimizer performs:
GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
Permutations for Starting Table :0
Join order[1]: DEPARTMENTS[D]#0 EMPLOYEES[E]#1
***************
Now joining: EMPLOYEES[E]#1
***************
NL Join
Outer table: Card: 27.00 Cost: 2.01 Resp: 2.01 Degree: 1 Bytes: 16
Access path analysis for EMPLOYEES
. . .
Best NL cost: 13.17
. . .
SM Join
SM cost: 6.08
resc: 6.08 resc_io: 4.00 resc_cpu: 2501688
resp: 6.08 resp_io: 4.00 resp_cpu: 2501688
. . .
SM Join (with index on outer)
Access Path: index (FullScan)
. . .
HA Join
HA cost: 4.57
resc: 4.57 resc_io: 4.00 resc_cpu: 678154
resp: 4.57 resp_io: 4.00 resp_cpu: 678154
Best:: JoinMethod: Hash
Cost: 4.57 Degree: 1 Resp: 4.57 Card: 106.00 Bytes: 27
. . .
***********************
Join order[2]: EMPLOYEES[E]#1 DEPARTMENTS[D]#0
. . .
***************
Now joining: DEPARTMENTS[D]#0
***************
. . .
HA Join
HA cost: 4.58
resc: 4.58 resc_io: 4.00 resc_cpu: 690054
resp: 4.58 resp_io: 4.00 resp_cpu: 690054
Join order aborted: cost > best plan cost
***********************
The trace file shows the optimizer first trying the departments table as the outer
table in the join. The optimizer calculates the cost for three different join methods:
nested loops join (NL), sort merge (SM), and hash join (HA). The optimizer picks the
hash join as the most efficient method:
Best:: JoinMethod: Hash
Cost: 4.57 Degree: 1 Resp: 4.57 Card: 106.00 Bytes: 27
The optimizer then tries a different join order, using employees as the outer table.
This join order costs more than the previous join order, so it is abandoned.
The optimizer uses an internal cutoff to reduce the number of plans it tries when
finding the lowest-cost plan. The cutoff is based on the cost of the current best plan. If
the current best cost is large, then the optimizer explores alternative plans to find a
lower cost plan. If the current best cost is small, then the optimizer ends the search
swiftly because further cost improvement is not significant.
• Normal optimization
The optimizer compiles the SQL and generates an execution plan. The normal
mode generates a reasonable plan for most SQL statements. Under normal mode,
the optimizer operates with strict time constraints, usually a fraction of a second,
during which it must find an optimal plan.
See Also:
Adaptive Plans
An adaptive plan enables the optimizer to defer the final plan decision for a statement
until execution time.
See Also:
An adaptive plan for this statement shows two possible plans, one with a nested loops
join and the other with a hash join.
------------------------------------------------------------------------------------------------
|Id | Operation | Name |Starts|E-Rows|A-Rows|A-Time|Buff|Reads|OMem|1Mem|O/1/M|
------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | |1| | 13|00:00:00.10 |21 |17 | | | |
|*1| HASH JOIN | |1|4| 13|00:00:00.10 |21 |17 | 2061K| 2061K|1/0/0|
|*2| TABLE ACCESS FULL| ORDER_ITEMS |1|4| 13|00:00:00.07 | 5 | 4 | | | |
| 3| TABLE ACCESS FULL| PRODUCT_INFORMATION |1|1|288|00:00:00.03 |16 |13 | | | |
------------------------------------------------------------------------------------------------
1 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
2 - filter(("O"."UNIT_PRICE"=15 AND "QUANTITY">1))
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
Note
-----
- this is an adaptive plan
A nested loops join is preferable if the database can avoid scanning a significant
portion of product_information because its rows are filtered by the join predicate.
If few rows are filtered, however, then scanning the right table in a hash join is
preferable.
The following graphic shows the adaptive process. For the query in the preceding
example, the adaptive portion of the default plan contains two subplans, each of
which uses a different join method. The optimizer automatically determines when
each join method is optimal, depending on the cardinality of the left side of the join.
The statistics collector buffers enough rows coming from the order_items table to
determine which join method to use. If the row count is below the threshold
determined by the optimizer, then the optimizer chooses the nested loops join;
otherwise, the optimizer chooses the hash join. In this case, the row count coming from
the order_items table is above the threshold, so the optimizer chooses a hash join
for the final plan, and disables buffering.
Nested Hash
Loops Join
Statistics
Collector
The optimizer disables the statistics collector after making the decision,
and lets the rows pass through.
Nested Hash
Loops Join
Statistics
Collector
1 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
2 - filter(("O"."UNIT_PRICE"=15 AND "QUANTITY">1))
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
Note
-----
- this is an adaptive plan
See Also:
Query
Coordinator
P1 P2 P3 P4
departments P5 employees
P6
P7
P8
Contrast the broadcast distribution example in Figure 4-6 with an example that returns
a greater number of rows. In the following plan, the threshold is 8, or twice the
specified DOP of 4. However, because the statistics collector (Step 10) discovers that
the number of rows (27) is greater than the threshold (8), the optimizer chooses a
hybrid hash distribution rather than a broadcast distribution. (The time column
should show 00:00:01, but shows 0:01 so the plan can fit the page.)
EXPLAIN PLAN FOR
SELECT /*+ parallel(4) full(e) full(d) */ department_name, sum(salary)
FROM employees e, departments d
WHERE d.department_id=e.department_id
GROUP BY department_name;
7 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")
Note
-----
- Degree of Parallelism is 4 because of hint
32 rows selected.
See Also:
Oracle Database VLDB and Partitioning Guide to learn more about parallel data
redistribution techniques
Adaptive Statistics
The quality of the plans that the optimizer generates depends on the quality of the
statistics. Some query predicates become too complex to rely on base table statistics
alone, so the optimizer augments these statistics with adaptive statistics.
The following topics describe types of adaptive statistics:
• Dynamic Statistics
• Automatic Reoptimization
Dynamic Statistics
During the compilation of a SQL statement, the optimizer decides whether to use
dynamic statistics by considering whether the available statistics are sufficient to
generate an optimal execution plan. If the available statistics are insufficient, then the
optimizer uses dynamic statistics to augment the statistics. One type of dynamic
statistics is the information gathered by dynamic sampling. The optimizer can use
dynamic statistics for table scans, index access, joins, and GROUP BY operations, thus
improving the quality of optimizer decisions.
See Also:
“Dynamic Statistics” to learn more about dynamic statistics and optimizer
statistics in general
Automatic Reoptimization
Whereas adaptive plans help decide between multiple subplans, they are not feasible
for all kinds of plan changes. For example, a query with an inefficient join order might
perform suboptimally, but adaptive plans do not support adapting the join order
during execution. In these cases, the optimizer considers automatic reoptimization. In
See Also:
2. After the first execution, the optimizer disables monitoring for statistics feedback.
3. If the query executes again, then the optimizer uses the corrected cardinality
estimates instead of its usual estimates.
Example 4-2 Statistics Feedback
This example shows how the database uses statistics feedback to adjust incorrect
estimates.
1. The user oe runs the following query of the orders, order_items, and
product_information tables:
SELECT o.order_id, v.product_name
FROM orders o,
( SELECT order_id, product_name
2. Querying the plan in the cursor shows that the estimated rows (E-Rows) is far
fewer than the actual rows (A-Rows).
3. The user oe reruns the following query of the orders, order_items, and
product_information tables:
SELECT o.order_id, v.product_name
FROM orders o,
( SELECT order_id, product_name
FROM order_items o, product_information p
WHERE p.product_id = o.product_id
AND list_price < 50
AND min_price < 40 ) v
WHERE o.order_id = v.order_id;
4. Querying the plan in the cursor shows that the optimizer used statistics feedback
(shown in the Note) for the second execution, and also chose a different plan.
In the preceding output, the estimated number of rows (269) matches the actual
number of rows.
2. At the end of the initial execution, the optimizer compares the following:
3. If the query executes again, then the optimizer uses the performance statistics
gathered during the initial execution to better determine a degree of parallelism
for the statement.
Note:
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPD package
• Maintain plan history, and possibly SQL plan baselines, for a set of SQL statements
• Detect potentially better plans that are not in the SQL plan baseline
The optimizer uses the normal cost-based search method.
See Also:
Managing SQL Plan Baselines
• OR Expansion
• View Merging
• Predicate Pushing
• Subquery Unnesting
• Star Transformation
• In-Memory Aggregation
• Table Expansion
• Join Factorization
OR Expansion
In OR expansion, the optimizer transforms a query with a WHERE clause containing OR
operators into a query that uses the UNION ALL operator. The database can perform
OR expansion for various reasons. For example, it may enable more efficient access
paths or alternative join methods that avoid Cartesian products. As always, the
optimizer performs the expansion only if the cost of the transformed statement is
lower than the cost of the original statement.
In the following example, user sh creates a concatenated index on the
sales.prod_id and sales.promo_idcolumns, and then queries the sales table
using an OR condition:
CREATE INDEX sales_prod_promo_ind
ON sales(prod_id, promo_id);
SELECT *
FROM sales
WHERE promo_id=33
OR prod_id=136;
View Merging
In view merging, the optimizer merges the query block representing a view into the
query block that contains it. View merging can improve plans by enabling the
optimizer to consider additional join orders, access methods, and other
transformations.
For example, after a view has been merged and several tables reside in one query
block, a table inside a view may permit the optimizer to use join elimination to
remove a table outside the view. For certain simple views in which merging always
leads to a better plan, the optimizer automatically merges the view without
considering cost. Otherwise, the optimizer uses cost to make the determination. The
optimizer may choose not to merge a view for many reasons, including cost or validity
restrictions.
If OPTIMIZER_SECURE_VIEW_MERGING is true (default), then Oracle Database
performs checks to ensure that view merging and predicate pushing do not violate the
security intentions of the view creator. To disable these additional security checks for a
specific view, you can grant the MERGE VIEW privilege to a user for this view. To
disable additional security checks for all views for a specific user, you can grant the
MERGE ANY VIEW privilege to that user.
Note:
You can use hints to override view merging rejected because of cost or
heuristics, but not validity.
See Also:
• Oracle Database SQL Language Reference for more information about the
MERGE ANY VIEW and MERGE VIEW privileges
– GROUP BY
– DISTINCT
– Outer join
– MODEL
– CONNECT BY
– Set operators
– Aggregation
• The view participates in an outer join, and does not meet one of the several
additional validity requirements that determine whether the view can be merged.
Example 5-3 Simple View Merging
The following query joins the hr.employees table with the dept_locs_v view,
which returns the street address for each department. dept_locs_v is a join of the
departments and locations tables.
SELECT e.first_name, e.last_name, dept_locs_v.street_address,
dept_locs_v.postal_code
FROM employees e,
( SELECT d.department_id, d.department_name,
l.street_address, l.postal_code
FROM departments d, locations l
WHERE d.location_id = l.location_id ) dept_locs_v
WHERE dept_locs_v.department_id = e.department_id
AND e.last_name = 'Smith';
The database can execute the preceding query by joining departments and
locations to generate the rows of the view, and then joining this result to
employees. Because the query contains the view dept_locs_v, and this view
contains two tables, the optimizer must use one of the following join orders:
View merging merges the tables from the view into the outer query block, removing
the inner query block. After view merging, the query is as follows:
SELECT e.first_name, e.last_name, l.street_address, l.postal_code
FROM employees e, departments d, locations l
WHERE d.location_id = l.location_id
AND d.department_id = e.department_id
AND e.last_name = 'Smith';
Because all three tables appear in one query block, the optimizer can choose from the
following six join orders:
See Also:
The Oracle Optimizer blog at https://blogs.oracle.com/optimizer/
to learn about outer join view merging, which is a special case of simple view
merging
The following query finds all of the customers from the United States who have
bought at least 100 fur-trimmed sweaters:
SELECT c.cust_id, c.cust_first_name, c.cust_last_name, c.cust_email
FROM customers c, products p, cust_prod_totals_v
WHERE c.country_id = 52790
AND c.cust_id = cust_prod_totals_v.cust_id
AND cust_prod_totals_v.total > 100
AND cust_prod_totals_v.prod_id = p.prod_id
AND p.prod_name = 'T3 Faux Fur-Trimmed Sweater';
The transformed query is cheaper than the untransformed query, so the optimizer
chooses to merge the view. In the untransformed query, the GROUP BY operator
applies to the entire sales table in the view. In the transformed query, the joins to
products and customers filter out a large portion of the rows from the sales table,
so the GROUP BY operation is lower cost. The join is more expensive because the
sales table has not been reduced, but it is not much more expensive because the
GROUP BY operation does not reduce the size of the row set very much in the original
query. If any of the preceding characteristics were to change, merging the view might
no longer be lower cost. The final plan, which does not include a view, is as follows:
--------------------------------------------------------
| Id | Operation | Name | Cost (%CPU)|
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 2101 (18)|
|* 1 | FILTER | | |
| 2 | HASH GROUP BY | | 2101 (18)|
|* 3 | HASH JOIN | | 2099 (18)|
|* 4 | HASH JOIN | | 1801 (19)|
|* 5 | TABLE ACCESS FULL| PRODUCTS | 96 (5)|
| 6 | TABLE ACCESS FULL| SALES | 1620 (15)|
|* 7 | TABLE ACCESS FULL | CUSTOMERS | 296 (11)|
--------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(SUM("QUANTITY_SOLD")>100)
3 - access("C"."CUST_ID"="CUST_ID")
4 - access("PROD_ID"="P"."PROD_ID")
5 - filter("P"."PROD_NAME"='T3 Faux Fur-Trimmed Sweater')
7 - filter("C"."COUNTRY_ID"='US')
After determining that view merging produces a lower-cost plan, the optimizer
rewrites the query into this equivalent query:
SELECT nwvw.cust_id, nwvw.cust_first_name, nwvw.cust_last_name, nwvw.cust_email
FROM ( SELECT DISTINCT(c.rowid), p.rowid, s.prod_id, s.cust_id,
c.cust_first_name, c.cust_last_name, c.cust_email
FROM customers c, products p, sales s
WHERE c.country_id = 52790
AND c.cust_id = s.cust_id
AND s.prod_id = p.prod_id
AND p.prod_name = 'T3 Faux Fur-Trimmed Sweater' ) nwvw;
|* 4 | HASH JOIN | |
|* 5 | TABLE ACCESS FULL| PRODUCTS |
| 6 | TABLE ACCESS FULL| SALES |
|* 7 | TABLE ACCESS FULL | CUSTOMERS |
-------------------------------------------
The preceding plan contains a view named vm_nwvw_1, known as a projection view,
even after view merging has occurred. Projection views appear in queries in which a
DISTINCT view has been merged, or a GROUP BY view is merged into an outer query
block that also contains GROUP BY, HAVING, or aggregates. In the latter case, the
projection view contains the GROUP BY, HAVING, and aggregates from the original
outer query block.
In the preceding example of a projection view, when the optimizer merges the view, it
moves the DISTINCT operator to the outer query block, and then adds several
additional columns to maintain semantic equivalence with the original query.
Afterward, the query can select only the desired columns in the SELECT list of the
outer query block. The optimization retains all of the benefits of view merging: all
tables are in one query block, the optimizer can permute them as needed in the final
join order, and the DISTINCT operation has been delayed until after all of the joins
complete.
Predicate Pushing
In predicate pushing, the optimizer "pushes" the relevant predicates from the
containing query block into the view query block. For views that are not merged, this
technique improves the subplan of the unmerged view because the database can use
the pushed-in predicates to access indexes or to use as filters.
For example, suppose you create a table hr.contract_workers as follows:
DROP TABLE contract_workers;
CREATE TABLE contract_workers AS (SELECT * FROM employees where 1=2);
INSERT INTO contract_workers VALUES (306, 'Bill', 'Jones', 'BJONES',
'555.555.2000', '07-JUN-02', 'AC_ACCOUNT', 8300, 0,205, 110);
INSERT INTO contract_workers VALUES (406, 'Jill', 'Ashworth', 'JASHWORTH',
'555.999.8181', '09-JUN-05', 'AC_ACCOUNT', 8300, 0,205, 50);
INSERT INTO contract_workers VALUES (506, 'Marcie', 'Lunsford', 'MLUNSFORD',
'555.888.2233', '22-JUL-01', 'AC_ACCOUNT', 8300, 0,205, 110);
COMMIT;
CREATE INDEX contract_workers_index ON contract_workers(department_id);
You create a view that references employees and contract_workers. The view is
defined with a query that uses the UNION set operator, as follows:
CREATE VIEW all_employees_vw AS
( SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM employees )
UNION
( SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM contract_workers );
SELECT last_name
FROM all_employees_vw
WHERE department_id = 50;
Because the view is a UNION set query, the optimizer cannot merge the view's query
into the accessing query block. Instead, the optimizer can transform the accessing
statement by pushing its predicate, the WHERE clause condition department_id=50,
into the view's UNION set query. The equivalent transformed query is as follows:
SELECT last_name
FROM ( SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM employees
WHERE department_id=50
UNION
SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM contract_workers
WHERE department_id=50 );
The transformed query can now consider index access in each of the query blocks.
Subquery Unnesting
In subquery unnesting, the optimizer transforms a nested query into an equivalent
join statement, and then optimizes the join. This transformation enables the optimizer
to consider the subquery tables during access path, join method, and join order
selection. The optimizer can perform this transformation only if the resulting join
statement is guaranteed to return the same rows as the original statement, and if
subqueries do not contain aggregate functions such as AVG.
For example, suppose you connect as user sh and execute the following query:
SELECT *
FROM sales
WHERE cust_id IN ( SELECT cust_id
FROM customers );
If the optimizer cannot transform a complex statement into a join statement, it selects
execution plans for the parent statement and the subquery as though they were
separate statements. The optimizer then executes the subquery and uses the rows
returned to execute the parent query. To improve execution speed of the overall
execution plan, the optimizer orders the subplans efficiently.
The optimizer looks for any materialized views that are compatible with the user
query, and then selects one or more materialized views to rewrite the user query. The
use of materialized views to rewrite a query is cost-based. That is, the optimizer does
not rewrite the query when the plan generated without the materialized views has a
lower cost than the plan generated with the materialized views.
Consider the following materialized view, cal_month_sales_mv, which aggregates
the dollar amount sold each month:
CREATE MATERIALIZED VIEW cal_month_sales_mv
ENABLE QUERY REWRITE
AS
SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars
FROM sales s, times t
WHERE s.time_id = t.time_id
GROUP BY t.calendar_month_desc;
Assume that sales number is around one million in a typical month. The view has the
precomputed aggregates for the dollar amount sold for each month. Consider the
following query, which asks for the sum of the amount sold for each month:
SELECT t.calendar_month_desc, SUM(s.amount_sold)
FROM sales s, times t
WHERE s.time_id = t.time_id
GROUP BY t.calendar_month_desc;
Without query rewrite, the database must access sales directly and compute the sum
of the amount sold. This method involves reading many million rows from sales,
which invariably increases query response time. The join also further slows query
response because the database must compute the join on several million rows. With
query rewrite, the optimizer transparently rewrites the query as follows:
SELECT calendar_month, dollars
FROM cal_month_sales_mv;
See Also:
Oracle Database Data Warehousing Guide to learn more about query rewrite
Star Transformation
Star transformation is an optimizer transformation that avoids full table scans of fact
tables in a star schema. This section contains the following topics:
products times
sales
(amount_sold,
quantity_sold)
Fact Table
customers channels
See Also:
Oracle Database Data Warehousing Guide to learn more about star schemas
• All the predicates on dimension tables are part of the semijoin subquery predicate.
• The dimension columns are not in the SELECT list, GROUP BY clause, and so on.
• true
The optimizer performs the star transformation by identifying the fact and
constraint dimension tables automatically. The optimizer performs the star
transformation only if the cost of the transformed plan is lower than the
alternatives. Also, the optimizer attempts temporary table transformation
automatically whenever materialization improves performance (see “Temporary
Table Transformation: Scenario”).
• false (default)
The optimizer does not perform star transformations.
• TEMP_DISABLE
This value is identical to true except that the optimizer does not attempt
temporary table transformation.
See Also:
In this example, sales is the fact table, and the other tables are dimension tables. The
sales table contains one row for every sale of a product, so it could conceivably
contain billions of sales records. However, only a few products are sold to customers
in California through the Internet for the specified quarters.
Example 5-7 Star Transformation
This example shows a star transformation of the query in Example 5-6. The
transformation avoids a full table scan of sales.
SELECT c.cust_city, t.calendar_quarter_desc, SUM(s.amount_sold) sales_amount
FROM sales s, times t, customers c
WHERE s.time_id = t.time_id
AND s.cust_id = c.cust_id
AND c.cust_state_province = 'CA'
AND t.calendar_quarter_desc IN ('1999-01','1999-02')
AND s.time_id IN ( SELECT time_id
FROM times
WHERE calendar_quarter_desc IN('1999-01','1999-02') )
AND s.cust_id IN ( SELECT cust_id
FROM customers
WHERE cust_state_province='CA' )
AND s.channel_id IN ( SELECT channel_id
FROM channels
WHERE channel_desc = 'Internet' )
GROUP BY c.cust_city, t.calendar_quarter_desc;
In line 10, the database applies the AND operator to the merged bitmaps. Assume that
after the database has performed all OR operations, the resulting bitmap for channels
is 100000... If the database performs an AND operation on this bitmap and the
bitmap from customers subquery, then the result is as follows:
100000... # channels bitmap after all OR operations performed
111000... # customers bitmap after all OR operations performed
---------
100000... # bitmap result of AND operation for channels and customers
In line 9, the database generates the corresponding rowids of the final bitmap. The
database retrieves rows from the sales fact table using the rowids (line 26). In our
example, the database generate only one rowid, which corresponds to the first row,
and thus fetches only a single row instead of scanning the entire sales table.
-------------------------------------------------------------------------------
| Id | Operation | Name
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |
| 1 | HASH GROUP BY |
|* 2 | HASH JOIN |
|* 3 | TABLE ACCESS FULL | CUSTOMERS
|* 4 | HASH JOIN |
|* 5 | TABLE ACCESS FULL | TIMES
| 6 | VIEW | VW_ST_B1772830
| 7 | NESTED LOOPS |
| 8 | PARTITION RANGE SUBQUERY |
| 9 | BITMAP CONVERSION TO ROWIDS|
| 10 | BITMAP AND |
| 11 | BITMAP MERGE |
| 12 | BITMAP KEY ITERATION |
| 13 | BUFFER SORT |
|* 14 | TABLE ACCESS FULL | CHANNELS
|* 15 | BITMAP INDEX RANGE SCAN| SALES_CHANNEL_BIX
| 16 | BITMAP MERGE |
| 17 | BITMAP KEY ITERATION |
| 18 | BUFFER SORT |
|* 19 | TABLE ACCESS FULL | TIMES
|* 20 | BITMAP INDEX RANGE SCAN| SALES_TIME_BIX
| 21 | BITMAP MERGE |
| 22 | BITMAP KEY ITERATION |
| 23 | BUFFER SORT |
|* 24 | TABLE ACCESS FULL | CUSTOMERS
|* 25 | BITMAP INDEX RANGE SCAN| SALES_CUST_BIX
| 26 | TABLE ACCESS BY USER ROWID | SALES
-------------------------------------------------------------------------------
2 -
access("ITEM_1"="C"."CUST_ID")
3 -
filter("C"."CUST_STATE_PROVINCE"='CA')
4 -
access("ITEM_2"="T"."TIME_ID")
5 -
filter(("T"."CALENDAR_QUARTER_DESC"='1999-01'
OR "T"."CALENDAR_QUARTER_DESC"='1999-02'))
14 - filter("CH"."CHANNEL_DESC"='Internet')
15 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")
19 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01'
OR "T"."CALENDAR_QUARTER_DESC"='1999-02'))
20 - access("S"."TIME_ID"="T"."TIME_ID")
24 - filter("C"."CUST_STATE_PROVINCE"='CA')
25 - access("S"."CUST_ID"="C"."CUST_ID")
Note
-----
- star transformation used for this statement
Example 5-10 Partial Execution Plan for Star Transformation Using Temporary
Table
The following example shows an edited version of the execution plan for the query in
Example 5-9:
-------------------------------------------------------------------------------
| Id | Operation | Name
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |
| 1 | TEMP TABLE TRANSFORMATION |
| 2 | LOAD AS SELECT |
|* 3 | TABLE ACCESS FULL | CUSTOMERS
| 4 | HASH GROUP BY |
|* 5 | HASH JOIN |
| 6 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6613_C716F
|* 7 | HASH JOIN |
|* 8 | TABLE ACCESS FULL | TIMES
| 9 | VIEW | VW_ST_A3F94988
| 10 | NESTED LOOPS |
| 11 | PARTITION RANGE SUBQUERY |
| 12 | BITMAP CONVERSION TO ROWIDS|
| 13 | BITMAP AND |
| 14 | BITMAP MERGE |
| 15 | BITMAP KEY ITERATION |
| 16 | BUFFER SORT |
|* 17 | TABLE ACCESS FULL | CHANNELS
|* 18 | BITMAP INDEX RANGE SCAN| SALES_CHANNEL_BIX
| 19 | BITMAP MERGE |
| 20 | BITMAP KEY ITERATION |
| 21 | BUFFER SORT |
|* 22 | TABLE ACCESS FULL | TIMES
|* 23 | BITMAP INDEX RANGE SCAN| SALES_TIME_BIX
| 24 | BITMAP MERGE |
| 25 | BITMAP KEY ITERATION |
| 26 | BUFFER SORT |
| 27 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6613_C716F
|* 28 | BITMAP INDEX RANGE SCAN| SALES_CUST_BIX
| 29 | TABLE ACCESS BY USER ROWID | SALES
-------------------------------------------------------------------------------
3 - filter("C"."CUST_STATE_PROVINCE"='CA')
5 - access("ITEM_1"="C0")
7 - access("ITEM_2"="T"."TIME_ID")
8 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01' OR
"T"."CALENDAR_QUARTER_DESC"='1999-02'))
17 - filter("CH"."CHANNEL_DESC"='Internet')
18 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")
22 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01' OR
"T"."CALENDAR_QUARTER_DESC"='1999-02'))
23 - access("S"."TIME_ID"="T"."TIME_ID")
28 - access("S"."CUST_ID"="C0")
Lines 1, 2, and 3 of the plan materialize the customers subquery into the temporary
table. In line 6, the database scans the temporary table (instead of the subquery) to
build the bitmap from the fact table. Line 27 scans the temporary table for joining back
instead of scanning customers. The database does not need to apply the filter on
customers on the temporary table because the filter is applied while materializing
the temporary table.
In-Memory Aggregation
The basic approach of in-memory aggregation is to aggregate while scanning. To
optimize query blocks involving aggregation and joins from a single large table to
multiple small tables, such as in a typical star query, the transformation uses KEY
VECTOR and VECTOR GROUP BY operations. These operations use efficient in-
memory arrays for joins and aggregation, and are especially effective when the
underlying tables are in-memory columnar tables.
3. Aggregating rows
The unit of work between stages is called a data flow operator (DFO). VECTOR GROUP
BY aggregation uses a DFO for each dimension to create a key vector structure and
temporary table. When aggregating measure columns from the fact table, the database
uses this key vector to translate a fact join key to its dense grouping key. The late
materialization step joins on the dense grouping keys to the temporary tables.
Key Vector
A key vector is a data structure that maps between dense join keys and dense
grouping keys. A dense key is a numeric key that is stored as a native integer and has
a range of values. A dense join key represents all join keys whose join columns come
from a particular fact table or dimension. A dense grouping key represents all
grouping keys whose grouping columns come from a particular fact table or
dimension. A key vector enables fast lookups.
Example 5-11 Key Vector
Assume that the hr.locations tables has values for country_id as shown (only
the first few results are shown):
SQL> SELECT country_id FROM locations;
CO
--
IT
IT
JP
JP
US
US
US
US
CA
CA
CN
In the preceding array, 1 is the dense grouping key for country_id='US'. The 0
values indicate rows in locations that do not match this filter. If a query uses the
filter WHERE country_id IN ('US','JP'), then the array might look as follows,
where 2 is the dense grouping key for JP and 1 is the dense grouping key for US:
0
0
2
2
1
1
1
1
0
0
0
DFO 1
VECTOR GROUP BY
DFO 0
dimension scan
a. Process all the joins and aggregations using the key vectors created in the
preceding phase.
DFO 4
hash join 2
DFO 3 DFO 2
temporary table 2 hash join 1
HASH GROUP BY
DFO 1
temporary table 1
DFO 0
VECTOR GROUP BY
fact scan
• Table hints
You can use the following pairs of hints:
See Also:
Oracle Database SQL Language Reference to learn more about the
VECTOR_TRANSFORM_FACT and VECTOR_TRANSFORM_DIMS hints
• Step 1: Key Vector and Temporary Table Creation for geography Dimension
• Step 2: Key Vector and Temporary Table Creation for products Dimension
USA WA spokane 3
USA CA SF 7
USA CA LA 8
9 1 150
8 2 100
4 3 110
2 30 130
6 20 400
3 1 100
1 7 120
3 8 130
4 3 200
A manager asks the business question, "How many Acme products in each
subcategory were sold online in Washington, and how many were sold in California?"
To answer this question, an analytic query of the sales_online fact table joins the
products and geography dimension tables as follows:
SELECT p.category, p.subcategory, g.country, g.state, SUM(s.amount)
FROM sales_online s, products p, geography g
WHERE s.geog_id = g.geog_id
AND s.prod_id = p.prod_id
AND g.state IN ('WA','CA')
AND p.manuf = 'ACME'
GROUP BY category, subcategory, country, state
Step 1: Key Vector and Temporary Table Creation for geography Dimension
In the first phase of VECTOR GROUP BY aggregation for this query, the database
creates a dense grouping key for each city/state combination for cities in the states of
Washington or California. In Table 5-6, the 1 is the USA,WA grouping key, and the 2 is
the USA,CA grouping key.
USA WA spokane 3 1
USA CA SF 7 2
USA CA LA 8 2
A key vector for the geography table looks like the array represented by the final
column in Table 5-5. The values are the geography dense grouping keys. Thus, the
key vector indicates which rows in sales_online meet the geography.state
filter criteria (a sale made in the state of CA or WA) and which country/state group each
row belongs to (either the USA,WA group or USA,CA group).
9 1 150 0
8 2 100 1
4 3 110 1
2 30 130 0
6 20 400 0
3 1 100 0
1 7 120 2
3 8 130 2
4 3 200 1
Table 5-6 shows rows in the tt_geography temporary table. The dense grouping key
for the USA,WA combination is 1, and the dense grouping key for the USA,CA
combination is 2.
USA CA 2
Step 2: Key Vector and Temporary Table Creation for products Dimension
The database creates a dense grouping key for each distinct category/subcategory
combination of an Acme product. For example, in Table 5-7, the 4 is dense grouping
key for an Acme electric switch.
A key vector for the products table might look like the array represented by the final
column in Table 5-8. The values represent the products dense grouping key. For
example, the 4 represents the online sale of an Acme electric switch. Thus, the key
vector indicates which rows in sales_online meet the products filter criteria (a
sale of an Acme product).
9 1 150 0
8 2 100 4
4 3 110 1
2 30 130 0
6 20 400 0
3 1 100 2
1 7 120 3
3 8 130 2
4 3 200 1
sport ball 2
electric bulb 3
electric switch 4
The preceding transformation is not an exact rendition of the internal SQL, which is
much more complicated, but a conceptual representation designed to illustrate the
basic concept.
9 1 150
8 2 100 4 1
4 3 110 1 1
2 30 130
6 20 400
3 1 100 2
1 7 120 3 2
3 8 130 2 2
4 3 200 1 1
As shown in Table 5-11, the database retrieves only those rows from sales_online
with non-null values for both dense grouping keys, indicating rows that satisfy all the
filtering criteria.
3 4 200 1 1
7 1 120 3 2
8 3 130 2 2
dgkp/dgkg 1 2
1 110,200
2 130
3 120
4 100
00:00:01| 1| 28|
| 21| TABLE ACCESS FULL | SYS_TEMP_0FD9D6645_11CBE8 | 5 | 125| 2 (0)|
00:00:01| | |
------------------------------------------------------------------------------------------------------
-------
Note
-----
- vector transformation used for this statement
45 rows selected.
Table Expansion
In table expansion, the optimizer generates a plan that uses indexes on the read-
mostly portion of a partitioned table, but not on the active portion of the table. This
section contains the following topics:
• In many databases, only a small portion of the data is actively updated through
DML.
Table expansion takes advantage of index-based plans for tables that have high update
volume. You can configure a table so that an index is only created on the read-mostly
portion of the data, and does not suffer the overhead burden of index maintenance on
the active portions of the data. Thus, table expansion reaps the benefit of improved
performance without suffering the ill effects of index maintenance.
See Also:
Assumptions
This scenario assumes the following:
• You want to run a star query against the sh.sales table, which is range-
partitioned on the time_id column.
• You want to disable indexes on specific partitions to see the benefits of table
expansion.
As shown in the Pstart and Pstop columns in the following plan, the optimizer
determines from the filter that only 16 of the 28 partitions in the table must be
accessed:
Plan hash value: 3087065703
--------------------------------------------------------------------------
|Id| Operation | Name |Pstart|Pstop|
--------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |
| 1| PARTITION RANGE ITERATOR | | 13 | 28 |
| 2| TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES | 13 | 28 |
| 3| BITMAP CONVERSION TO ROWIDS | | | |
|*4| BITMAP INDEX SINGLE VALUE |SALES_PROD_BIX| 13 | 28 |
--------------------------------------------------------------------------
4 - access("PROD_ID"=38)
After the optimizer has determined the partitions to be accessed, it considers any
index that is usable on all of those partitions. In the preceding plan, the optimizer
chose to use the sales_prod_bix bitmap index.
The preceding DDL disables the index on partition 1, which contains all sales
from before 1996.
Note:
4. Execute the query of sales again, and then query DBMS_XPLAN to obtain the plan.
The output shows that the plan did not change:
Plan hash value: 3087065703
---------------------------------------------------------------------------
|Id| Operation | Name |Pstart|Pstop
---------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |
| 1| PARTITION RANGE ITERATOR | | 13 | 28 |
| 2| TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES | 13 | 28 |
| 3| BITMAP CONVERSION TO ROWIDS | | | |
|*4| BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX| 13 | 28 |
---------------------------------------------------------------------------
4 - access("PROD_ID"=38)
The plan is the same because the disabled index partition is not relevant to the
query. If all partitions that the query accesses are indexed, then the database can
answer the query using the index. Because the query only accesses partitions 16
through 28, disabling the index on partition 1 does not affect the plan.
By disabling the indexes on a partition that the query does need to access, the
query can no longer use this index (without table expansion).
---------------------------------------------------------------------------
| Id| Operation | Name |Pstart|Pstop
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |
| 1 | PARTITION RANGE ITERATOR | | 13 | 28 |
|*2 | TABLE ACCESS FULL | SALES | 13 | 28 |
---------------------------------------------------------------------------
7. With table expansion, the optimizer rewrites the original query as follows:
SELECT *
FROM sales
WHERE time_id >= TO_DATE('2000-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND time_id < TO_DATE('2003-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND prod_id = 38
UNION ALL
SELECT *
FROM sales
WHERE time_id >= TO_DATE('2003-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND time_id < TO_DATE('2004-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND prod_id = 38;
In the preceding query, the first query block in the UNION ALL accesses the
partitions that are indexed, while the second query block accesses the partition
that is not. The two subqueries enable the optimizer to choose to use the index in
the first query block, if it is more optimal than using a table scan of all of the
partitions that are accessed.
---------------------------------------------------------------------------
|Id| Operation | Name |Pstart|Pstop|
---------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |
| 1| VIEW | VW_TE_2 | | |
| 2| UNION-ALL | | | |
| 3| PARTITION RANGE ITERATOR | | 13| 27|
| 4| TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES | 13| 27|
| 5| BITMAP CONVERSION TO ROWIDS | | | |
|*6| BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX| 13| 27|
6 - access("PROD_ID"=38)
8 - filter("PROD_ID"=38)
As shown in the preceding plan, the optimizer uses a UNION ALL for two query
blocks (Step 2). The optimizer chooses an index to access partitions 13 to 27 in the
first query block (Step 6). Because no index is available for partition 28, the
optimizer chooses a full table scan in the second query block (Step 8).
Assumptions
This scenario assumes the following:
• The last partition of sales is actively being updated, as is often the case with time-
partitioned tables.
3. Query the cursor using DBMS_XPLAN, which shows the following plan:
---------------------------------------------------------------------------
|Id| Operation | Name | Pstart| Pstop |
---------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |
| 1| HASH GROUP BY | | | |
| 2| VIEW |VW_TE_14 | | |
| 3| UNION-ALL | | | |
| 4| HASH JOIN | | | |
| 5| TABLE ACCESS FULL |TIMES | | |
| 6| VIEW |VW_ST_1319B6D8 | | |
| 7| NESTED LOOPS | | | |
| 8| PARTITION RANGE SUBQUERY | |KEY(SQ)|KEY(SQ)|
| 9| BITMAP CONVERSION TO ROWIDS| | | |
|10| BITMAP AND | | | |
|11| BITMAP MERGE | | | |
|12| BITMAP KEY ITERATION | | | |
|13| BUFFER SORT | | | |
|14| TABLE ACCESS FULL |CHANNELS | | |
|15| BITMAP INDEX RANGE SCAN|SALES_CHANNEL_BIX|KEY(SQ)|KEY(SQ)|
|16| BITMAP MERGE | | | |
|17| BITMAP KEY ITERATION | | | |
|18| BUFFER SORT | | | |
|19| TABLE ACCESS FULL |TIMES | | |
|20| BITMAP INDEX RANGE SCAN|SALES_TIME_BIX |KEY(SQ)|KEY(SQ)|
|21| BITMAP MERGE | | | |
|22| BITMAP KEY ITERATION | | | |
|23| BUFFER SORT | | | |
|24| TABLE ACCESS FULL |CUSTOMERS | | |
|25| BITMAP INDEX RANGE SCAN|SALES_CUST_BIX |KEY(SQ)|KEY(SQ)|
|26| TABLE ACCESS BY USER ROWID |SALES | ROWID | ROWID |
|27| NESTED LOOPS | | | |
|28| NESTED LOOPS | | | |
|29| NESTED LOOPS | | | |
|30| NESTED LOOPS | | | |
|31| PARTITION RANGE SINGLE | | 28 | 28 |
|32| TABLE ACCESS FULL |SALES | 28 | 28 |
|33| TABLE ACCESS BY INDEX ROWID|CHANNELS | | |
|34| INDEX UNIQUE SCAN |CHANNELS_PK | | |
|35| TABLE ACCESS BY INDEX ROWID |CUSTOMERS | | |
|36| INDEX UNIQUE SCAN |CUSTOMERS_PK | | |
|37| INDEX UNIQUE SCAN |TIMES_PK | | |
|38| TABLE ACCESS BY INDEX ROWID |TIMES | | |
---------------------------------------------------------------------------
The preceding plan uses table expansion. The UNION ALL branch that is accessing
every partition except the last partition uses star transformation. Because the
indexes on partition 28 are disabled, the database accesses the final partition using
a full table scan.
Join Factorization
In the cost-based transformation known as join factorization, the optimizer can
factorize common computations from branches of a UNION ALL query.
This section contains the following topics:
In the preceding query, table t1 appears in both UNION ALL branches, as does the
filter predicate t1.c1 > 1 and the join predicate t1.c1 = t2.c1. Without any
transformation, the database must perform the scan and the filtering on table t1 twice,
one time for each branch.
Example 5-14 Factorized Query
The following query uses join factorization to transform the query in Example 5-13.
SELECT t1.c1, VW_JF_1.item_2
FROM t1, (SELECT t2.c1 item_1, t2.c2 item_2
FROM t2, t3
WHERE t2.c2 = t3.c2
AND t2.c2 = 2
UNION ALL
SELECT t2.c1 item_1, t2.c2 item_2
FROM t2, t4
WHERE t2.c3 = t4.c3) VW_JF_1
WHERE t1.c1 = VW_JF_1.item_1
AND t1.c1 > 1
In this case, because table t1 is factorized, the database performs the table scan and
the filtering on t1 only one time. If t1 is large, then this factorization avoids the huge
performance cost of scanning and filtering t1 twice.
Note:
If the branches in a UNION ALL query have clauses that use the DISTINCT
function, then join factorization is not valid.
Before join factorization, the database must join t1, t2, and t3 before joining them
with t5.
Example 5-16 Factorization of t1 from View V
If join factorization factorizes t1 from view V, as shown in the following query, then
the database can join t1 with t5.:
SELECT *
FROM t5, ( SELECT t1.c1, VW_JF_1.item_2
FROM t1, (SELECT t2.c1 item_1, t2.c2 item_2
FROM t2, t3
WHERE t2.c2 = t3.c2
AND t2.c2 = 2
UNION ALL
SELECT t2.c1 item_1, t2.c2 item_2
FROM t2, t4
WHERE t2.c3 = t4.c3) VW_JF_1
WHERE t1.c1 = VW_JF_1.item_1
AND t1.c1 > 1 )
WHERE t5.c1 = V.c1
The preceding query transformation opens up new join orders. However, join
factorization imposes specific join orders. For example, in the preceding query, tables
t2 and t3 appear in the first branch of the UNION ALL query in view VW_JF_1. The
database must join t2 with t3 before it can join with t1, which is not defined within
the VW_JF_1 view. The imposed join order may not necessarily be the best join order.
For this reason, the optimizer performs join factorization using the cost-based
transformation framework. The optimizer calculate the cost of the plans with and
without join factorization, and then chooses the cheapest plan.
The following example shows the transformation. Table t2 now no longer appears in
the UNION ALL branches of the subquery.
SELECT VW_JF_1.item_2, t2.c2
FROM t2, (SELECT t1.c1 item_1, t1.c2 item_2
FROM t1
WHERE t1.c1 = 1
UNION ALL
SELECT t1.c1 item_1, t1.c2 item_2
FROM t1
WHERE t1.c1 = 2) VW_JF_1
WHERE VW_JF_1.item_1 = t2.c1(+)
See Also:
Joins
See Also:
Oracle Database SQL Language Reference to learn about the EXPLAIN PLAN
statement
Note:
To avoid possible SQL performance regression that may result from execution
plan changes, consider using SQL plan management.
• Different Schemas
• Different Costs
See Also:
“Managing SQL Plan Baselines ”
Different Schemas
Schemas can differ for the following reasons:
• The user explaining the statement is different from the user running the statement.
Two users might be pointing to different objects in the same database, resulting in
different execution plans.
Different Costs
Even if the schemas are the same, the optimizer can choose different execution plans
when the costs are different. Some factors that affect the costs include the following:
• Full scans
It is best to use EXPLAIN PLAN to determine an access plan, and then later prove that it
is the optimal plan through testing. When evaluating a plan, examine the statement's
actual resource consumption.
See Also:
See Also:
Performing Application Tracing
Oracle recommends that you drop and rebuild your local PLAN_TABLE table after
upgrading the version of the database because the columns might change. This can
cause scripts to fail or cause TKPROF to fail, if you are specifying the table.
If you do not want to use the name PLAN_TABLE, create a new synonym after running
the catplan.sql script. For example:
CREATE OR REPLACE PUBLIC SYNONYM my_plan_table for plan_table$
• Use the SQL script CATPLAN.SQL to create a sample output table called
PLAN_TABLE in your schema. See “Guidelines for Creating PLAN_TABLE”.
• Include the EXPLAIN PLAN FOR clause before the SQL statement.
• After issuing the EXPLAIN PLAN statement, use a script or package provided by
Oracle Database to display the most recent plan table output. See “Displaying
PLAN_TABLE Output”.
• The execution order in EXPLAIN PLAN output begins with the line that is the
furthest indented to the right. The next step is the parent of that line. If two lines
are indented equally, then the top line is normally executed first.
Note:
– The EXPLAIN PLAN output tables in this chapter were displayed with the
utlxpls.sql script.
– The steps in the EXPLAIN PLAN output in this chapter may be different on
your system. The optimizer may choose different execution plans,
depending on database configurations.
To explain a SQL statement, use the EXPLAIN PLAN FOR clause immediately before
the statement. For example:
EXPLAIN PLAN FOR
SELECT last_name FROM employees;
This explains the plan into the PLAN_TABLE table. You can then select the execution
plan from PLAN_TABLE. See “Displaying PLAN_TABLE Output”.
See Also:
• UTLXPLS.SQL
This script displays the plan table output for serial processing. Example 6-5 is an
example of the plan table output when using the UTLXPLS.SQL script.
• UTLXPLP.SQL
This script displays the plan table output including parallel execution columns.
– A plan table name if you are using a table different than PLAN_TABLE
– A format option that determines the level of detail: BASIC, SERIAL, TYPICAL,
and ALL
Examples of using DBMS_XPLAN to display PLAN_TABLE output are:
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY('MY_PLAN_TABLE', 'st1','TYPICAL'));
See Also:
Oracle Database PL/SQL Packages and Types Reference for more information
about the DBMS_XPLAN package
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 189 | 8 (13)| 00:00:01 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 3 | 189 | 8 (13)| 00:00:01 |
| 3 | MERGE JOIN | | 3 | 141 | 5 (20)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | JOBS | 19 | 513 | 2 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN | JOB_ID_PK | 19 | | 1 (0)| 00:00:01 |
|* 6 | SORT JOIN | | 3 | 60 | 3 (34)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 3 | 60 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 3 | | 1 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | DEPT_ID_PK | 1 | | 0 (0)| 00:00:01 |
| 10 | TABLE ACCESS BY INDEX ROWID | DEPARTMENTS | 1 | 16 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
6 - access("E"."JOB_ID"="J"."JOB_ID")
filter("E"."JOB_ID"="J"."JOB_ID")
8 - access("E"."EMPLOYEE_ID"<103)
9 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
• Use the CONNECT BY clause to walk the tree from parent to child, the join keys
being STATEMENT_ID = PRIOR STATEMENT_ID and PARENT_ID = PRIOR ID.
• Use the pseudo-column LEVEL (associated with CONNECT BY) to indent the
children.
SELECT cardinality "Rows",
lpad(' ',level-1)||operation||' '||options||' '||object_name "Plan"
FROM PLAN_TABLE
CONNECT BY prior id = parent_id
AND prior statement_id = statement_id
START WITH id = 0
AND statement_id = 'st1'
ORDER BY id;
Rows Plan
------- ----------------------------------------
SELECT STATEMENT
TABLE ACCESS FULL EMPLOYEES
The NULL in the Rows column indicates that the optimizer does not have any
statistics on the table. Analyzing the table shows the following:
Rows Plan
------- ----------------------------------------
16957 SELECT STATEMENT
16957 TABLE ACCESS FULL EMPLOYEES
You can also select the COST. This is useful for comparing execution plans or for
understanding why the optimizer chooses one execution plan over another.
Note:
Examples of the output from this statement are shown in Example 7-4 and Example
7-1.
Example 7-1 EXPLAIN PLAN for Statement ID ex_plan1
The following plan shows execution of a SELECT statement. The table employees is
accessed using a full table scan. Every row in the table employees is accessed, and
the WHERE clause criteria is evaluated for every row.
EXPLAIN PLAN
SET statement_id = 'ex_plan1' FOR
SELECT phone_number
FROM employees
WHERE phone_number LIKE '650%';
---------------------------------------
| Id | Operation | Name |
---------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS FULL| EMPLOYEES |
---------------------------------------
SELECT PLAN_TABLE_OUTPUT
----------------------------------------
| Id | Operation | Name |
----------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | INDEX RANGE SCAN| EMP_NAME_IX |
----------------------------------------
• PLAN_TABLE Columns
Assumptions
This tutorial assumes the following:
SELECT product_name
FROM order_items o, product_information p
WHERE o.unit_price = 15
AND quantity > 1
AND p.product_id = o.product_id
2. Query orders.
For example, use the following statement:
SELECT o.order_id, v.product_name
FROM orders o,
( SELECT order_id, product_name
FROM order_items o, product_information p
WHERE p.product_id = o.product_id
AND list_price < 50
AND min_price < 40 ) v
WHERE o.order_id = v.order_id;
The following sample output has been reformatted to fit on the page. In this plan,
the optimizer chooses a nested loops join. The original optimizer estimates are
shown in the E-Rows column, whereas the actual statistics gathered during
execution are shown in the A-Rows column. In the MERGE JOIN operation, the
difference between the estimated and actual number of rows is significant.
--------------------------------------------------------------------------------------------
|Id| Operation | Name |Start|E-Rows|A-Rows|A-Time|Buff|OMem|1Mem|O/1/M|
--------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | 1| | 269|00:00:00.09|1338| | | |
| 1| NESTED LOOPS | | 1| 1| 269|00:00:00.09|1338| | | |
| 2| MERGE JOIN CARTESIAN| | 1| 4|9135|00:00:00.03| 33| | | |
|*3| TABLE ACCESS FULL |PRODUCT_INFORMAT| 1| 1| 87|00:00:00.01| 32| | | |
| 4| BUFFER SORT | | 87|105|9135|00:00:00.01| 1|4096|4096|1/0/0|
| 5| INDEX FULL SCAN | ORDER_PK | 1|105| 105|00:00:00.01| 1| | | |
|*6| INDEX UNIQUE SCAN | ORDER_ITEMS_UK |9135| 1| 269|00:00:00.03|1305| | | |
--------------------------------------------------------------------------------------------
5. View the execution plan in the cursor by using the same SELECT statement that
you ran in Step 3.
The following example shows that the optimizer has chosen a different plan,
using a hash join. The Note section shows that the optimizer used statistics
feedback to adjust its cost estimates for the second execution of the query, thus
illustrating automatic reoptimization.
--------------------------------------------------------------------------------------------
|Id| Operation |Name |Start|E-Rows|A-Rows|A-Time|Buff|Reads|OMem|1Mem|O/1/M|
--------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | 1 | |269|00:00:00.02|60|1| | | |
| 1| NESTED LOOPS | | 1 |269|269|00:00:00.02|60|1| | | |
|*2| HASH JOIN | | 1 |313|269|00:00:00.02|39|1|1000K|1000K|1/0/0|
|*3| TABLE ACCESS FULL |PRODUCT_INFORMA| 1 | 87| 87|00:00:00.01|15|0| | | |
| 4| INDEX FAST FULL SCAN|ORDER_ITEMS_UK | 1 |665|665|00:00:00.01|24|1| | | |
|*5| INDEX UNIQUE SCAN |ORDER_PK |269| 1|269|00:00:00.01|21|0| | | |
--------------------------------------------------------------------------------------------
2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))
5 - access("O"."ORDER_ID"="ORDER_ID")
Note
-----
- statistics feedback used for this statement
The second statement executed, which is child number 1, used statistics feedback.
CPU time, elapsed time, and buffer gets are all significantly lower.
Sample output appears below. Based on statistics collected at run time (Step 4),
the optimizer chose a hash join rather than the nested loops join. The dashes (-)
indicate the steps in the nested loops plan that the optimizer considered but do
not ultimately choose. The switch illustrates the adaptive plan feature.
-------------------------------------------------------------------------------
|Id | Operation | Name |Rows|Bytes|Cost(%CPU)|Time |
-------------------------------------------------------------------------------
| 0| SELECT STATEMENT | |4|128|7(0)|00:00:01|
| *1| HASH JOIN | |4|128|7(0)|00:00:01|
|- 2| NESTED LOOPS | | | | | |
|- 3| NESTED LOOPS | | |128|7(0)|00:00:01|
|- 4| STATISTICS COLLECTOR | | | | | |
Note
-----
- this is an adaptive plan (rows marked '-' are inactive)
See Also:
• “Adaptive Plans”
• “Table 7-8”
• Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_XPLAN
customer is the smallest table while transaction is the largest. A typical OLTP
query might retrieve transaction information about a specific customer account. The
query drives from the customer table. The goal in this case is to minimize logical
I/O, which typically minimizes other critical resources including physical I/O and
CPU time.
For parallel queries, the driving table is usually the largest table because the database
can use parallel query. It would not be efficient to use parallel query in this case
because only a few rows from each table are ultimately accessed. However, what if it
were necessary to identify all customers who had transactions of a certain type last
month? It would be more efficient to drive from the transaction table because no
limiting conditions exist on the customer table. The database would join rows from
the transaction table to the account table, and finally to the customer table. In
this case, the indexes used on the account and customer table are probably highly
selective primary key or unique indexes rather than non-unique indexes used in the
first query. Because the transaction table is large and the column is not selective, it
would be beneficial to use parallel query driving from the transaction table.
Parallel operations include the following:
• PARALLEL_TO_PARALLEL
• PARALLEL_TO_SERIAL
A PARALLEL_TO_SERIAL operation is always the step that occurs when the query
coordinator consumes rows from a parallel operation. Another type of operation
that does not occur in this query is a SERIAL operation. If these types of operations
occur, then consider making them parallel operations to improve performance
because they too are potential bottlenecks.
• PARALLEL_FROM_SERIAL
• PARALLEL_TO_PARALLEL
If the workloads in each step are relatively equivalent, then the
PARALLEL_TO_PARALLEL operations generally produce the best performance.
• PARALLEL_COMBINED_WITH_CHILD
• PARALLEL_COMBINED_WITH_PARENT
A PARALLEL_COMBINED_WITH_PARENT operation occurs when the database
performs the step simultaneously with the parent step.
If a parallel step produces many rows, then the QC may not be able to consume the
rows as fast as they are produced. Little can be done to improve this situation.
See Also:
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows| Bytes |Cost %CPU| TQ |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 107 | 2782 | 3 (34) | | | |
| 1 | PX COORDINATOR | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | 107 | 2782 | 3 (34) | Q1,01 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 107 | 2782 | 3 (34) | Q1,01 | PCWP | |
| 4 | PX RECEIVE | | 107 | 2782 | 3 (34) | Q1,01 | PCWP | |
| 5 | PX SEND HASH | :TQ10000 | 107 | 2782 | 3 (34) | Q1,00 | P->P | HASH |
| 6 | HASH GROUP BY | | 107 | 2782 | 3 (34) | Q1,00 | PCWP | |
| 7 | PX BLOCK ITERATOR | | 107 | 2782 | 2 (0) | Q1,00 | PCWP | |
| 8 | TABLE ACCESS FULL| EMP2 | 107 | 2782 | 2 (0) | Q1,00 | PCWP | |
------------------------------------------------------------------------------------------------
One set of parallel execution servers scans EMP2 in parallel, while the second set
performs the aggregation for the GROUP BY operation. The PX BLOCK ITERATOR row
source represents the splitting up of the table EMP2 into pieces to divide the scan
workload between the parallel execution servers. The PX SEND and PX RECEIVE row
sources represent the pipe that connects the two sets of parallel execution servers as
rows flow up from the parallel scan, get repartitioned through the HASH table queue,
and then read by and aggregated on the top set. The PX SEND QC row source
represents the aggregated values being sent to the QC in random (RAND) order. The
PX COORDINATOR row source represents the QC or Query Coordinator which controls
and schedules the parallel plan appearing below it in the plan tree.
Note:
Queries using bitmap join index indicate the bitmap join index access path.
The operation for bitmap join index is the same as bitmap index.
AND c2 <> 6
OR c3 BETWEEN 10 AND 20;
SELECT STATEMENT
TABLE ACCESS T BY INDEX ROWID
BITMAP CONVERSION TO ROWID
BITMAP OR
BITMAP MINUS
BITMAP MINUS
BITMAP INDEX C1_IND SINGLE VALUE
BITMAP INDEX C2_IND SINGLE VALUE
BITMAP INDEX C2_IND SINGLE VALUE
BITMAP MERGE
BITMAP INDEX C3_IND RANGE SCAN
To view the EXPLAIN PLAN for this query, use the following command:
EXPLAIN PLAN FOR
SELECT /*+ result_cache */ deptno, avg(sal)
FROM emp
GROUP BY deptno;
The EXPLAIN PLAN output for this query should look similar to the following:
--------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time |
--------------------------------------------------------------------------------
|0| SELECT STATEMENT | | 11 | 77 | 4 (25)| 00:00:01|
|1| RESULT CACHE |b06ppfz9pxzstbttpbqyqnfbmy| | | | |
|2| HASH GROUP BY | | 11 | 77 | 4 (25)| 00:00:01|
|3| TABLE ACCESS FULL| EMP |107 | 749| 3 (0) | 00:00:01|
--------------------------------------------------------------------------------
partition-wise join is possible if one of the joined tables is partitioned on its join
column and the table is parallelized.
A join is implemented using full partition-wise join if the partition row source appears
before the join row source in the EXPLAIN PLAN output. Full partition-wise joins are
possible only if both joined tables are equi-partitioned on their respective join
columns. Examples of execution plans for several types of partitioning follow.
The database creates a partition row source on top of the table access row source. It
iterates over the set of partitions to be accessed. In this example, the partition iterator
covers all partitions (option ALL), because a predicate was not used for pruning. The
PARTITION_START and PARTITION_STOP columns of the PLAN_TABLE show access
to all partitions from 1 to 5.
For the next example, consider the following statement:
EXPLAIN PLAN FOR
SELECT *
FROM emp_range
WHERE hire_date >= TO_DATE('1-JAN-1996','DD-MON-YYYY');
-----------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 399 | 2 | | |
| 1 | PARTITION RANGE ITERATOR| | 3 | 399 | 2 | 4 | 5 |
| *2 | TABLE ACCESS FULL |EMP_RANGE| 3 | 399 | 2 | 4 | 5 |
-----------------------------------------------------------------------
In the previous example, the partition row source iterates from partition 4 to 5 because
the database prunes the other partitions using a predicate on hire_date.
-----------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 133 | 2 | | |
| 1 | PARTITION RANGE SINGLE| | 1 | 133 | 2 | 1 | 1 |
|* 2 | TABLE ACCESS FULL | EMP_RANGE | 1 | 133 | 2 | 1 | 1 |
-----------------------------------------------------------------------
In the previous example, only partition 1 is accessed and known at compile time; thus,
there is no need for a partition row source.
Note:
Oracle Database displays the same information for hash partitioned objects,
except the partition row source name is PARTITION HASH instead of
PARTITION RANGE. Also, with hash partitioning, pruning is only possible
using equality or IN-list predicates.
-----------------------------------------------------------------------
|Id| Operation | Name | Rows | Bytes |Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0| SELECT STATEMENT | | 10120 | 1314K| 78 | | |
| 1| PARTITION RANGE ALL| | 10120 | 1314K| 78 | 1 | 5 |
| 2| PARTITION HASH ALL| | 10120 | 1314K| 78 | 1 | 3 |
| 3| TABLE ACCESS FULL| EMP_COMP | 10120 | 1314K| 78 | 1 | 15 |
-----------------------------------------------------------------------
This example shows the plan when Oracle Database accesses all subpartitions of all
partitions of a composite object. The database uses two partition row sources for this
purpose: a range partition row source to iterate over the partitions and a hash partition
row source to iterate over the subpartitions of each accessed partition.
In the following example, the range partition row source iterates from partition 1 to 5,
because the database performs no pruning. Within each partition, the hash partition
row source iterates over subpartitions 1 to 3 of the current partition. As a result, the
table access row source accesses subpartitions 1 to 15. In other words, it accesses all
subpartitions of the composite object.
EXPLAIN PLAN FOR
SELECT *
FROM emp_comp
WHERE hire_date = TO_DATE('15-FEB-1998', 'DD-MON-YYYY');
-----------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes |Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 2660 | 17 | | |
| 1 | PARTITION RANGE SINGLE| | 20 | 2660 | 17 | 5 | 5 |
| 2 | PARTITION HASH ALL | | 20 | 2660 | 17 | 1 | 3 |
|* 3 | TABLE ACCESS FULL | EMP_COMP | 20 | 2660 | 17 | 13 | 15 |
-----------------------------------------------------------------------
In the previous example, only the last partition, partition 5, is accessed. This partition
is known at compile time, so the database does not need to show it in the plan. The
hash partition row source shows accessing of all subpartitions within that partition;
that is, subpartitions 1 to 3, which translates into subpartitions 13 to 15 of the
emp_comp table.
Now consider the following statement:
EXPLAIN PLAN FOR
SELECT *
FROM emp_comp
WHERE department_id = 20;
------------------------------------------------------------------------
| Id | Operation |Name |Rows | Bytes |Cost|Pstart|Pstop|
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 13433 | 78 | | |
| 1 | PARTITION RANGE ALL | | 101 | 13433 | 78 | 1 | 5 |
| 2 | PARTITION HASH SINGLE| | 101 | 13433 | 78 | 3 | 3 |
|* 3 | TABLE ACCESS FULL | EMP_COMP | 101 | 13433 | 78 | | |
------------------------------------------------------------------------
In the previous example, the predicate deptno = 20 enables pruning on the hash
dimension within each partition, so Oracle Database only needs to access a single
subpartition. The number of that subpartition is known at compile time, so the hash
partition row source is not needed.
Finally, consider the following statement:
VARIABLE dno NUMBER;
EXPLAIN PLAN FOR
SELECT *
FROM emp_comp
WHERE department_id = :dno;
-----------------------------------------------------------------------
| Id| Operation | Name |Rows| Bytes |Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101| 13433 | 78 | | |
| 1 | PARTITION RANGE ALL | | 101| 13433 | 78 | 1 | 5 |
| 2 | PARTITION HASH SINGLE| | 101| 13433 | 78 | KEY | KEY |
The last two examples are the same, except that department_id = :dno replaces
deptno = 20. In this last case, the subpartition number is unknown at compile time,
and a hash partition row source is allocated. The option is SINGLE for that row source,
because Oracle Database accesses only one subpartition within each partition. The
PARTITION_START and PARTITION_STOP is set to KEY, which means that Oracle
Database determines the number of subpartitions at run time.
------------------------------------------------------------------------------------------------
|Id| Operation |Name |Row|Byte|Cost|Pstart|Pstop|TQ|IN-OUT|PQ Distrib|
------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | |284 |16188|6 | | | | | |
| 1| PX COORDINATOR | | | | | | | | | |
| 2| PX SEND QC (RANDOM) |:TQ10001 |284 |16188|6 | | | Q1,01 |P->S |QC (RAND) |
|*3| HASH JOIN | |284 |16188|6 | | | Q1,01 |PCWP | |
| 4| PX PARTITION RANGE ALL | |284 |7668 |2 | 1 | 2 | Q1,01 |PCWC | |
| 5| TABLE ACCESS FULL |EMP_RANGE_DID|284 |7668 |2 | 1 | 2 | Q1,01 |PCWP | |
| 6| BUFFER SORT | | | | | | | Q1,01 |PCWC | |
| 7| PX RECEIVE | | 21 | 630 |2 | | | Q1,01 |PCWP | |
| 8| PX SEND PARTITION (KEY)|:TQ10000 | 21 | 630 |2 | | | |S->P |PART (KEY)|
| 9| TABLE ACCESS FULL |DEPT2 | 21 | 630 |2 | | | | | |
------------------------------------------------------------------------------------------------
The execution plan shows that the table dept2 is scanned serially and all rows with
the same partitioning column value of emp_range_did (department_id) are sent
through a PART (KEY), or partition key, table queue to the same parallel execution
server doing the partial partition-wise join.
------------------------------------------------------------------------------------------------
| Id| Operation | Name |Rows |Bytes |Cost|Pstart|Pstop|TQ |IN-OUT|PQ Distrib|
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 445 | 17800 | 5 | | | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) |:TQ10001| 445 | 17800 | 5 | | | Q1,01 | P->S | QC (RAND)|
|*3 | HASH JOIN | | 445 | 17800 | 5 | | | Q1,01 | PCWP | |
| 4 | PX PARTITION RANGE ALL | | 107 | 1070 | 3 | 1 | 5 | Q1,01 | PCWC | |
| 5 | PX PARTITION HASH ALL | | 107 | 1070 | 3 | 1 | 3 | Q1,01 | PCWC | |
| 6 | TABLE ACCESS FULL |EMP_COMP| 107 | 1070 | 3 | 1 | 15| Q1,01 | PCWP | |
| 7 | PX RECEIVE | | 21 | 630 | 1 | | | Q1,01 | PCWP | |
| 8 | PX SEND PARTITION (KEY)|:TQ10000| 21 | 630 | 1 | | | Q1,00 | P->P |PART (KEY)|
| 9 | PX BLOCK ITERATOR | | 21 | 630 | 1 | | | Q1,00 | PCWC | |
|10 | TABLE ACCESS FULL |DEPT2 | 21 | 630 | 1 | | | Q1,00 | PCWP | |
------------------------------------------------------------------------------------------------
The plan shows that the optimizer selects partial partition-wise join from one of two
columns. The PX SEND node type is PARTITION(KEY) and the PQ Distrib column
contains the text PART (KEY), or partition key. This implies that the table dept2 is re-
partitioned based on the join column department_id to be sent to the parallel
execution servers executing the scan of EMP_COMP and the join.
------------------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost|Pstart|Pstop|TQ |IN-OUT|PQ Distrib|
------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | 106 | 2544 | 8 | | | | | |
| 1| PX COORDINATOR | | | | | | | | | |
The PX PARTITION HASH row source appears on top of the join row source in the plan
table output while the PX PARTITION RANGE row source appears over the scan of
emp_comp. Each parallel execution server performs the join of an entire hash partition
of emp_comp with an entire partition of dept_hash.
The INLIST ITERATOR operation iterates over the next operation in the plan for each
value in the IN-list predicate. The following sections describe the three possible types
of IN-list columns for partitioned tables and indexes.
The KEY(INLIST) designation for the partition start and stop keys specifies that an IN-
list predicate appears on the index start and stop keys.
PLAN_TABLE Columns
The PLAN_TABLE used by the EXPLAIN PLAN statement contains the columns listed in
Table 7-1.
POSITION NUMERIC For the first row of output, this indicates the
optimizer's estimated cost of executing the
statement. For the other rows, it indicates
the position relative to the other children of
the same parent.
Table 7-2 describes the values that can appear in the DISTRIBUTION column:
PARTITION (KEY) Maps rows to query servers based on the partitioning of a table or index using a set of
columns. Used for partial partition-wise join, PARALLEL INSERT, CREATE TABLE AS
SELECT of a partitioned table, and CREATE PARTITIONED GLOBAL INDEX.
HASH Maps rows to query servers using a hash function on the join key. Used for PARALLEL
JOIN or PARALLEL GROUP BY.
RANGE Maps rows to query servers using ranges of the sort key. Used when the statement
contains an ORDER BY clause.
BROADCAST Broadcasts the rows of the entire table to each query server. Used for a parallel join
when one table is very small compared to the other.
QC (ORDER) The QC consumes the input in order, from the first to the last query server. Used when
the statement contains an ORDER BY clause.
QC (RANDOM) The QC consumes the input randomly. Used when the statement does not have an
ORDER BY clause.
Table 7-3 lists each combination of OPERATION and OPTIONS produced by the
EXPLAIN PLAN statement and its meaning within an execution plan.
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
BITMAP INDEX SINGLE VALUE looks up the bitmap for a single key
value in the index.
RANGE SCAN retrieves bitmaps for a key value range.
FULL SCAN performs a full scan of a bitmap index if
there is no start or stop key.
BITMAP MINUS Subtracts bits of one bitmap from another. Row source
is used for negated predicates. Use this option only if
there are nonnegated predicates yielding a bitmap
from which the subtraction can take place. An
example appears in “Viewing Bitmap Indexes with
EXPLAIN PLAN”.
BITMAP KEY Takes each row from a table row source and finds the
ITERATION corresponding bitmap from a bitmap index. This set of
bitmaps are then merged into one bitmap in a
following BITMAP MERGE operation.
CUBE SCAN PARTIAL Uses an outer join for at least one dimension, and
OUTER inner joins for the other dimensions.
CUBE SCAN OUTER Uses outer joins for all cube access.
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
HASH JOIN Operation joining two sets of rows and returning the
(These are join result. This join method is useful for joining large data
operations.) sets of data (DSS, Batch). The join condition is an
efficient way of accessing the second table.
Query optimizer uses the smaller of the two tables/
data sources to build a hash table on the join key in
memory. Then it scans the larger table, probing the
hash table to find the joined rows.
INDEX FULL SCAN Retrieval of all rowids from an index when there is no
start or stop key. Indexed values are scanned in
ascending order.
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
INDEX FAST FULL Retrieval of all rowids (and column values) using
SCAN multiblock reads. No sorting order can be defined.
Compares to a full table scan on only the indexed
columns. Only available with the cost based
optimizer.
INLIST Iterates over the next operation in the plan for each
ITERATOR value in the IN-list predicate.
MERGE JOIN CARTESIAN Can result from 1 or more of the tables not having any
join conditions to any other tables in the statement.
Can occur even with a join and it may not be flagged
as CARTESIAN in the plan.
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
MAT_VIEW BY USER If the materialized view rows are located using user-
REWITE ACCESS ROWID supplied rowids.
NESTED LOOPS Operation accepting two sets of rows, an outer set and
(These are join an inner set. Oracle Database compares each row of
operations.) the outer set with each row of the inner set, returning
rows that satisfy a condition. This join method is
useful for joining small subsets of data (OLTP). The
join condition is an efficient way of accessing the
second table.
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
SORT GROUP BY Operation sorting a set of rows into groups for a query
PIVOT with a GROUP BY clause. The PIVOT option indicates a
pivot-specific optimization for the SORT GROUP BY
operator.
TABLE ACCESS HASH Retrieval of rows from table based on hash cluster key
value.
TABLE ACCESS BY ROWID Retrieval of rows from a table based on a rowid range.
RANGE
TABLE ACCESS BY USER If the table rows are located using user-supplied
ROWID rowids.
TABLE ACCESS BY INDEX If the table is nonpartitioned and rows are located
ROWID using index(es).
TABLE ACCESS BY GLOBAL If the table is partitioned and rows are located using
INDEX ROWID only global indexes.
Table 7-3 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
See Also:
• PLAN_TABLE Columns
View Description
V$SQL_SHARED_CURSOR Explains why a particular child cursor is not
shared with existing child cursors. Each column
identifies a specific reason why the cursor cannot
be shared.
The USE_FEEDBACK_STATS column shows
whether a child cursor fails to match because of
reoptimization.
PLAN_TABLE Columns
The PLAN_TABLE used by the EXPLAIN PLAN statement contains the columns listed in
Table 7-5.
Table 7-6 describes the values that can appear in the DISTRIBUTION column:
PARTITION (KEY) Maps rows to query servers based on the partitioning of a table or index using a set of
columns. Used for partial partition-wise join, PARALLEL INSERT, CREATE TABLE AS
SELECT of a partitioned table, and CREATE PARTITIONED GLOBAL INDEX.
HASH Maps rows to query servers using a hash function on the join key. Used for PARALLEL
JOIN or PARALLEL GROUP BY.
BROADCAST Broadcasts the rows of the entire table to each query server. Used for a parallel join
when one table is very small compared to the other.
QC (ORDER) The QC consumes the input in order, from the first to the last query server. Used when
the statement contains an ORDER BY clause.
QC (RANDOM) The QC consumes the input randomly. Used when the statement does not have an
ORDER BY clause.
Table 7-7 lists each combination of OPERATION and OPTIONS produced by the
EXPLAIN PLAN statement and its meaning within an execution plan.
BITMAP CONVERSION TO ROWIDS converts bitmap representations to actual rowids that you
can use to access the table.
FROM ROWIDS converts the rowids to a bitmap representation.
COUNT returns the number of rowids if the actual values are not
needed.
BITMAP INDEX SINGLE VALUE looks up the bitmap for a single key value in the
index.
RANGE SCAN retrieves bitmaps for a key value range.
FULL SCAN performs a full scan of a bitmap index if there is no start
or stop key.
BITMAP MERGE Merges several bitmaps resulting from a range scan into one bitmap.
BITMAP MINUS Subtracts bits of one bitmap from another. Row source is used for
negated predicates. This option is usable only if there are nonnegated
predicates yielding a bitmap from which the subtraction can take
place.
BITMAP KEY ITERATION Takes each row from a table row source and finds the corresponding
bitmap from a bitmap index. This set of bitmaps are then merged into
one bitmap in a following BITMAP MERGE operation.
Table 7-7 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
COUNT STOPKEY Count operation where the number of rows returned is limited by the
ROWNUM expression in the WHERE clause.
CUBE JOIN Joins a table or view on the left and a cube on the right.
See Oracle Database SQL Language Reference to learn about the
NO_USE_CUBE and USE_CUBE hints.
CUBE JOIN ANTI Uses an antijoin for a table or view on the left and a cube on the right.
CUBE JOIN ANTI SNA Uses an antijoin (single-sided null aware) for a table or view on the left
and a cube on the right. The join column on the right (cube side) is
NOT NULL.
CUBE JOIN OUTER Uses an outer join for a table or view on the left and a cube on the
right.
CUBE JOIN RIGHT SEMI Uses a right semijoin for a table or view on the left and a cube on the
right.
CUBE SCAN PARTIAL OUTER Uses an outer join for at least one dimension, and inner joins for the
other dimensions.
CUBE SCAN OUTER Uses outer joins for all cube access.
DOMAIN INDEX Retrieval of one or more rowids from a domain index. The options
column contain information supplied by a user-defined domain index
cost function, if any.
FOR UPDATE Operation retrieving and locking the rows selected by a query
containing a FOR UPDATE clause.
HASH GROUP BY Operation hashing a set of rows into groups for a query with a GROUP
BY clause.
HASH GROUP BY PIVOT Operation hashing a set of rows into groups for a query with a GROUP
BY clause. The PIVOT option indicates a pivot-specific optimization
for the HASH GROUP BY operator.
HASH JOIN Operation joining two sets of rows and returning the result. This join
(These are join method is useful for joining large data sets of data (DSS, Batch). The
operations.) join condition is an efficient way of accessing the second table.
Query optimizer uses the smaller of the two tables/data sources to
build a hash table on the join key in memory. Then it scans the larger
table, probing the hash table to find the joined rows.
Table 7-7 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
INDEX RANGE SCAN Retrieval of one or more rowids from an index. Indexed values are
scanned in ascending order.
INDEX RANGE SCAN Retrieval of one or more rowids from an index. Indexed values are
DESCENDING scanned in descending order.
INDEX FULL SCAN Retrieval of all rowids from an index when there is no start or stop
key. Indexed values are scanned in ascending order.
INDEX FULL SCAN Retrieval of all rowids from an index when there is no start or stop
DESCENDING key. Indexed values are scanned in descending order.
INDEX FAST FULL SCAN Retrieval of all rowids (and column values) using multiblock reads.
No sorting order can be defined. Compares to a full table scan on only
the indexed columns. Only available with the cost based optimizer.
INDEX SKIP SCAN Retrieval of rowids from a concatenated index without using the
leading column(s) in the index. Only available with the cost based
optimizer.
INLIST Iterates over the next operation in the plan for each value in the IN-list
ITERATOR predicate.
INTERSECTION Operation accepting two sets of rows and returning the intersection of
the sets, eliminating duplicates.
MERGE JOIN Operation accepting two sets of rows, each sorted by a value,
(These are join combining each row from one set with the matching rows from the
operations.) other, and returning the result.
MERGE JOIN OUTER Merge join operation to perform an outer join statement.
MERGE JOIN CARTESIAN Can result from 1 or more of the tables not having any join conditions
to any other tables in the statement. Can occur even with a join and it
may not be flagged as CARTESIAN in the plan.
Table 7-7 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
MAT_VIEW HASH Retrieval of rows from materialized view based on hash cluster key
REWITE ACCESS value.
MAT_VIEW BY ROWID RANGE Retrieval of rows from a materialized view based on a rowid range.
REWITE ACCESS
MAT_VIEW SAMPLE BY Retrieval of sampled rows from a materialized view based on a rowid
REWITE ACCESS ROWID RANGE range.
MAT_VIEW BY USER ROWID If the materialized view rows are located using user-supplied rowids.
REWITE ACCESS
MAT_VIEW BY INDEX ROWID If the materialized view is nonpartitioned and rows are located using
REWITE ACCESS index(es).
MAT_VIEW BY GLOBAL If the materialized view is partitioned and rows are located using only
REWITE ACCESS INDEX ROWID global indexes.
MAT_VIEW BY LOCAL INDEX If the materialized view is partitioned and rows are located using one
REWITE ACCESS ROWID or more local indexes and possibly some global indexes.
Partition Boundaries:
The partition boundaries might have been computed by:
A previous PARTITION step, in which case the PARTITION_START
and PARTITION_STOP column values replicate the values present in
the PARTITION step, and the PARTITION_ID contains the ID of the
PARTITION step. Possible values for PARTITION_START and
PARTITION_STOP are NUMBER(n), KEY, INVALID.
The MAT_VIEW REWRITE ACCESS or INDEX step itself, in which case
the PARTITION_ID contains the ID of the step. Possible values for
PARTITION_START and PARTITION_STOP are NUMBER(n), KEY, ROW
REMOVE_LOCATION (MAT_VIEW REWRITE ACCESS only), and
INVALID.
MINUS Operation accepting two sets of rows and returning rows appearing in
the first set but not in the second, eliminating duplicates.
NESTED LOOPS Operation accepting two sets of rows, an outer set and an inner set.
(These are join Oracle Database compares each row of the outer set with each row of
operations.) the inner set, returning rows that satisfy a condition. This join method
is useful for joining small subsets of data (OLTP). The join condition is
an efficient way of accessing the second table.
Table 7-7 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
PARTITION Iterates over the next operation in the plan for each partition in the
range given by the PARTITION_START and PARTITION_STOP
columns. PARTITION describes partition boundaries applicable to a
single partitioned object (table or index) or to a set of equipartitioned
objects (a partitioned table and its local indexes). The partition
boundaries are provided by the values of PARTITION_START and
PARTITION_STOP of the PARTITION. Refer to Table 7-4 for valid
values of partition start and stop.
PX ITERATOR BLOCK, CHUNK Implements the division of an object into block or chunk ranges
among a set of parallel execution servers.
PX SEND QC (RANDOM), Implements the distribution method taking place between two sets of
HASH, RANGE parallel execution servers. Shows the boundary between two sets and
how data is repartitioned on the send/producer side (QC or side. This
information was formerly displayed into the DISTRIBUTION column.
See Table 7-5.
SORT AGGREGATE Retrieval of a single row that is the result of applying a group function
to a group of selected rows.
SORT GROUP BY Operation sorting a set of rows into groups for a query with a GROUP
BY clause.
Table 7-7 (Cont.) OPERATION and OPTIONS Values Produced by EXPLAIN PLAN
SORT ORDER BY Operation sorting a set of rows for a query with an ORDER BY clause.
TABLE ACCESS CLUSTER Retrieval of rows from a table based on a value of an indexed cluster
key.
TABLE ACCESS HASH Retrieval of rows from table based on hash cluster key value.
TABLE ACCESS BY ROWID RANGE Retrieval of rows from a table based on a rowid range.
TABLE ACCESS SAMPLE BY Retrieval of sampled rows from a table based on a rowid range.
ROWID RANGE
TABLE ACCESS BY USER ROWID If the table rows are located using user-supplied rowids.
TABLE ACCESS BY INDEX ROWID If the table is nonpartitioned and rows are located using index(es).
TABLE ACCESS BY GLOBAL If the table is partitioned and rows are located using only global
INDEX ROWID indexes.
TABLE ACCESS BY LOCAL INDEX If the table is partitioned and rows are located using one or more local
ROWID indexes and possibly some global indexes.
Partition Boundaries:
The partition boundaries might have been computed by:
A previous PARTITION step, in which case the PARTITION_START
and PARTITION_STOP column values replicate the values present in
the PARTITION step, and the PARTITION_ID contains the ID of the
PARTITION step. Possible values for PARTITION_START and
PARTITION_STOP are NUMBER(n), KEY, INVALID.
The TABLE ACCESS or INDEX step itself, in which case the
PARTITION_ID contains the ID of the step. Possible values for
PARTITION_START and PARTITION_STOP are NUMBER(n), KEY, ROW
REMOVE_LOCATION (TABLE ACCESS only), and INVALID.
UNION Operation accepting two sets of rows and returns the union of the sets,
eliminating duplicates.
VIEW Operation performing a view's query and then returning the resulting
rows to another operation.
See Also:
Table 7-8 DBMS_XPLAN Functions and Parameters Relevant for Adaptive Queries
Functions Notes
DISPLAY_PLAN The FORMAT argument supports the modifier ADAPTIVE.
When you specify ADAPTIVE, the output includes the default
plan. For each dynamic subplan, the plan shows a list of the row
sources from the original that may be replaced, and the row
sources that would replace them.
If the format argument specifies the outline display, then the
function displays the hints for each option in the dynamic
subplan. If the plan is not an adaptive plan, then the function
displays the default plan.When you do not specify ADAPTIVE,
the plan is shown as-is, but with additional comments in the
Note section that show any row sources that are dynamic.
A row source is a set of rows returned by a step in the execution plan. A SQL operator
acts on a row source. A unary operator acts on one input, as with access paths. A
binary operator acts on two outputs, as with joins.
This part contains the following chapters:
• Joins
8
Optimizer Access Paths
Access Path Heap-Organized B-Tree Indexes and Bitmap Indexes Table Clusters
Tables IOTs
Full Table Scans x
Access Path Heap-Organized B-Tree Indexes and Bitmap Indexes Table Clusters
Tables IOTs
Bitmap Index Single x
Value
Bitmap Merge x
Cluster Scans x
Hash Scans x
• An external table is a read-only table whose metadata is stored in the database but
whose data is stored outside the database.
This section explains optimizer access paths for heap-organized tables, and contains
the following topics:
See Also:
See Also:
Oracle Database Concepts to learn about data block storage
The database can sometimes move a row in the bottom part of the block. For example,
if row movement is enabled, then the row can move because of partition key updates,
Flashback Table operations, shrink table operations, and so on. If the database moves a
row within a block, then the database updates the row directory entry to modify the
pointer. The rowid stays constant.
Oracle Database uses rowids internally for the construction of indexes. For example,
each key in a B-tree index is associated with a rowid that points to the address of the
associated row. Physical rowids provide the fastest possible access to a table row,
enabling the database to retrieve a row in as little as a single I/O.
See Also:
Direct path
read
Situations in which Oracle Database may perform direct path reads include:
• Parallel queries
See Also:
Oracle Database Performance Tuning Guide to learn about wait events for direct
path reads
• No index exists.
If no index exists, then the optimizer uses a full table scan.
• A SELECT COUNT(*) query is issued, and an index exists, but the indexed column
contains nulls.
The optimizer cannot use the index to count the number of table rows because the
index cannot contain null entries (see “B-Tree Indexes and Nulls”).
• The query predicate does not use the leading edge of a B-tree index.
For example, an index might exist on employees(first_name,last_name). If
a user issues a query with the predicate WHERE last_name='KING', then the
optimizer may not choose an index because column first_name is not in the
predicate. However, in this situation the optimizer may choose to use an index skip
scan (see “Index Skip Scans”).
See Also:
Because the blocks are adjacent, the database can speed up the scan by making I/O
calls larger than a single block, known as a multiblock read. The size of a read call
ranges from one block to the number of blocks specified by the
DB_FILE_MULTIBLOCK_READ_COUNT initialization parameter. For example, setting
this parameter to 4 instructs the database to read up to 4 blocks in a single call.
The algorithms for caching blocks during full table scans are complex. For example,
the database caches blocks differently depending on whether tables are small or large.
See Also:
• Table 14-1
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3 (100)| |
|* 1 | TABLE ACCESS FULL| EMPLOYEES | 98 | 6762 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------
1 - filter("SALARY">4000)
Note:
Rowids can change between versions. Accessing data based on position is not
recommended because rows can move. To learn more about rowids, see Oracle
Database Development Guide.
1. Obtains the rowids of the selected rows, either from the statement WHERE clause
or through an index scan of one or more indexes
Table access may be needed for columns in the statement not present in the index.
Step 2 of the following plan shows a range scan of the emp_emp_id_pk index on the
hr.employees table. The database uses the rowids obtained from the index to find
the corresponding rows from the employees table, and then retrieve them. The
BATCHED access shown in Step 1 means that the database retrieves a few rowids from
the index, and then attempts to access rows in block order to improve the clustering
and reduce the number of times that the database must access a block.
--------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |2(100)| |
| 1| TABLE ACCESS BY INDEX ROWID BATCHED|EMPLOYEES |16|1104|2 (0)|00:00:01|
|*2| INDEX RANGE SCAN |EMP_EMP_ID_PK|16| |1 (0)|00:00:01|
--------------------------------------------------------------------------------
2 - access("EMPLOYEE_ID">190)
• SAMPLE (sample_percent)
The database reads a specified percentage of rows in the table to perform a sample
table scan.
Note:
Block sampling is possible only during full table scans or index fast full scans.
If a more efficient execution path exists, then the database does not sample
blocks. To guarantee block sampling for a specific table or index, use the FULL
or INDEX_FFS hint.
See Also:
• Oracle Database SQL Language Reference to learn about the SAMPLE clause
The EXPLAIN PLAN output for this statement might look as follows:
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 68 | 3 (34)|
| 1 | TABLE ACCESS SAMPLE | EMPLOYEES | 1 | 68 | 3 (34)|
-------------------------------------------------------------------------
See Also:
• INMEMORY_QUERY
This parameter enables or disables in-memory queries for the database at the
session or system level. This parameter is helpful when you want to test workloads
with and without the use of the IM column store.
• OPTIMIZER_INMEMORY_AWARE
This parameter enables (TRUE) or disables (FALSE) all of the in-memory
enhancements made to the optimizer cost model, table expansion, bloom filters,
and so on. Setting the parameter to FALSE causes the optimizer to ignore the in-
memory property of tables during the optimization of SQL statements.
• OPTIMIZER_FEATURES_ENABLE
When set to values lower than 12.1.0.2, this parameter has the same effect as
setting OPTIMIZER_INMEMORY_AWARE to FALSE.
To enable or disable in-memory queries, you can specify the INMEMORY or
NO_INMEMORY hints, which are the per-query equivalent of the INMEMORY_QUERY
initialization parameter. If a SQL statement uses the INMEMORY hint, but the object it
references is not already loaded in the IM column store, then the database does not
wait for the object to be populated in the IM column store before executing the
statement. However, initial access of the object triggers the object population in the IM
column store.
See Also:
• Oracle Database SQL Language Reference to learn more about the INMEMORY
hints
The plan for this statement might look as follows, with the INMEMORY keyword in Step
2 indicating that some or all of the object was accessed from the IM column store:
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
See Also:
Branch Blocks
0..40
41..80
81..120
....
200..250
Leaf Blocks
See Also:
In a unique index, the index key does not include the rowid. The database sorts the
data only by the index key values, such as 0, 1, 2, and so on.
See Also:
Oracle Database Concepts for an overview of unique and nonunique indexes
column can contain nulls, making it a nullable column, but the employee_id column
cannot.
SQL> SELECT COUNT(*) FROM employees WHERE department_id IS NULL;
COUNT(*)
----------
1
COUNT(*)
----------
0
The following example shows that the optimizer chooses a full table scan for a query
of all department IDs in hr.employees. The optimizer cannot use the index on
employees.department_id because the index is not guaranteed to include entries
for every row in the table.
SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees;
Explained.
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3476115102
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 107 | 321 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| EMPLOYEES | 107 | 321 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
8 rows selected.
The following example shows the optimizer can use the index on department_id for
a query of a specific department ID because all non-null rows are indexed.
SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees WHERE department_id=10;
Explained.
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 67425611
--------------------------------------------------------------------------------
| Id| Operation | Name | Rows |Bytes| Cost (%CPU)| Time |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:0 0:01|
|*1 | INDEX RANGE SCAN| EMP_DEPARTMENT_IX | 1 | 3 | 1 (0)| 00:0 0:01|
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
1 - access("DEPARTMENT_ID"=10)
The following example shows that the optimizer chooses an index scan when the
predicate excludes null values:
SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees
WHERE department_id IS NOT NULL;
Explained.
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1590637672
--------------------------------------------------------------------------------
| Id| Operation | Name | Rows|Bytes| Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 106 | 318 | 1 (0)| 00:0 0:01 |
|*1 | INDEX FULL SCAN | EMP_DEPARTMENT_IX | 106 | 318 | 1 (0)| 00:0 0:01 |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
• A query predicate references all of the columns in a unique index key using an
equality operator, such as WHERE prod_id=10.
Execution Plan
----------------------------------------------------------
Plan hash value: 868081059
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| T_TABLE_IDX | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
You can use the INDEX(alias index_name) hint to specify the index to use, but
not a specific type of index access path.
See Also:
• Oracle Database Concepts for more details on index structures and for
detailed information on how a B-tree is searched
• Oracle Database SQL Language Reference to learn more about the INDEX hint
Branch Blocks
0..40
41..80
81..120
....
200..250
Leaf Blocks
--------------------------------------------------------------------------------
| Id| Operation | Name |Rows|Bytes|Cost (%CPU)|Time |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 1 (100)| |
| 1| TABLE ACCESS BY INDEX ROWID| PRODUCTS | 1 | 173 | 1 (0)| 00:00:01|
|* 2| INDEX UNIQUE SCAN | PRODUCTS_PK | 1 | | 0 (0)| |
--------------------------------------------------------------------------------
2 - access("PROD_ID"=19)
– department_id = :id
– AND combination of the preceding conditions for leading columns in the index,
such as department_id > :low AND department_id < :hi.
Note:
For the optimizer to consider a range scan, wild-card searches of the form
col1 LIKE '%ASD' must not be in a leading position.
Tip:
If you require sorted data, then use the ORDER BY clause, and do not rely on
an index. If an index can satisfy an ORDER BY clause, then the optimizer uses
this option and avoids a sort.
The optimizer considers an index range scan descending when an index can satisfy an
ORDER BY DESCENDING clause.
If the optimizer chooses a full table scan or another index, then a hint may be required
to force this access path. The INDEX(tbl_alias ix_name) and
See Also:
Oracle Database SQL Language Reference to learn more about the INDEX and
INDEX_DESC hints
Note:
In some cases, an index scan reads a set of index blocks, sorts the rowids, and
then reads a set of table blocks.
Thus, to scan the index, the database moves backward or forward through the leaf
blocks. For example, a scan for IDs between 20 and 40 locates the first leaf block that
has the lowest key value that is 20 or greater. The scan proceeds horizontally through
the linked list of leaf nodes until it finds a value greater than 40, and then stops.
Figure 8-4 illustrates an index range scan using ascending order. A statement requests
the employees records with the value 20 in the department_id column, which has
a nonunique index. In this example, 2 index entries for department 20 exist.
Branch Blocks
0..40
41..80
81..120
....
200..250
Leaf Blocks
-------------------------------------------------------------------------------------------
|Id | Operation | Name |Rows|Bytes|Cost(%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
|*1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 2 | 138 | 2 (0)|00:00:01|
1 - filter("SALARY">1000)
2 - access("DEPARTMENT_ID"=20)
2 - access("DEPARTMENT_ID"<20)
• A predicate references a column in the index. This column need not be the leading
column.
– All columns in the table and in the query are in the index.
Branch Blocks
0..40
41..80
81..120
....
200..250
Leaf Blocks
--------------------------------------------------------------------------------
|Id | Operation | Name |Rows|Bytes|Cost(%CPU)|Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | DEPT_ID_PK | 27 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Note:
Unlike a full scan, a fast full scan cannot eliminate a sort operation because it
does not read the index in order.
See Also:
Oracle Database SQL Language Reference to learn more about the INDEX hint
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 2 (100)| |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| DEPT_ID_PK | 27 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------
See Also:
• The leading column of a composite index is not specified in the query predicate.
For example, if the composite index key is (cust_gender,cust_email), then
the query predicate does not reference the cust_gender column.
• Few distinct values exist in the leading column of the composite index, but many
distinct values exist in the nonleading key of the index.
For example, if the composite index key is (cust_gender,cust_email), then
the cust_gender column has only two distinct values, but cust_email has
thousands.
Often, skip scanning index blocks is faster than scanning table blocks, and faster than
performing full index scans.
Conceptually, a portion of the index might look as follows, with the gender value of F
or M as the leading edge of the index.
. . .
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
M,[email protected],rowid
M,[email protected],rowid
. . .
You run the following query for a customer in the sh.customers table:
SELECT *
FROM sh.customers
WHERE cust_email = '[email protected]';
The database can use a skip scan of the customers_gender_email index even
though cust_gender is not specified in the WHERE clause. In the sample index, the
leading column cust_gender has two possible values: F and M. The database
logically splits the index into two. One subindex has the key F, with entries in the
following form:
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
F,[email protected],rowid
The second subindex has the key M, with entries in the following form:
M,[email protected],rowid
M,[email protected],rowid
When searching for the record for the customer whose email is
[email protected], the database searches the subindex with the leading value F
first, and then searches the subindex with the leading value M. Conceptually, the
database processes the query as follows:
( SELECT *
FROM sh.customers
WHERE cust_gender = 'F'
AND cust_email = '[email protected]' )
UNION ALL
( SELECT *
FROM sh.customers
WHERE cust_gender = 'M'
AND cust_email = '[email protected]' )
-----------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------------------
| 0|SELECT STATEMENT | | | |10(100)| |
| 1| TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS |33|6237| 10(0)|00:00:01|
|*2| INDEX SKIP SCAN | CUST_GENDER_EMAIL_IX |33| | 4(0)|00:00:01|
-----------------------------------------------------------------------------------------
2 - access("CUST_EMAIL"='[email protected]')
filter("CUST_EMAIL"='[email protected]')
See Also:
Oracle Database Concepts to learn more about skip scans
• A hash join of multiple indexes retrieves all data requested by the query, without
requiring table access.
• The cost of retrieving rows from the table is higher than reading the indexes
without retrieving rows from the table. An index join is often expensive. For
example, when scanning two indexes and joining them, it is often less costly to
choose the most selective index, and then probe the table.
You can specify an index join with the INDEX_JOIN(table_name) hint.
See Also:
Oracle Database SQL Language Reference
• Bitmap Merge
The database stores a bitmap index in a B-tree structure (see “Bitmap Storage”). The
database can search the B-tree quickly on the first part of the key, which is the set of
attributes on which the index is defined, and then obtain the corresponding rowid
range and bitmap.
See Also:
• Oracle Database Data Warehousing Guide for more information about bitmap
indexes
See Also:
Oracle Database SQL Language Reference to learn about the COUNT function
number of possible rows in a block is predetermined, the database can use the range
endpoints to determine the rowid of an arbitrary row in the range.
Note:
As shown in Table 8-3, bitmap indexes can include keys that consist entirely of null
values, unlike B-tree indexes. In Table 8-3, the null has a value of 1 for the 6th row in
the range, which means that the cust_marital_status value is null for the 6th row
in the range. Indexing nulls can be useful for some SQL statements, such as queries
with the aggregate function COUNT.
See Also:
The FROM and WHERE clause in the preceding CREATE statement represent the join
condition between the tables. The customers.cust_city column is the index key.
Each key value in the index represents a possible city in the customers table.
Conceptually, key values for the index might look as follows, with one bitmap
associated with each key value:
San Francisco 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 . . .
San Mateo 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 . . .
Smithville 1 0 0 0 1 0 0 1 0 0 1 0 1 0 0 . . .
.
.
.
Each bit in a bitmap corresponds to one row in the sales table. In the Smithville
key, the value 1 means that the first row in the sales table corresponds to a product
sold to a Smithville customer, whereas the value 0 means that the second row
corresponds to a product not sold to a Smithville customer.
Consider the following query of the number of separate sales to Smithville customers:
SELECT COUNT (*)
FROM sales s, customers c
WHERE c.cust_id = s.cust_id
AND c.cust_city = 'Smithville';
The following plan shows that the database reads the Smithville bitmap to derive
the number of Smithville sales (Step 4), thereby avoiding the necessity of joining
customers and sales to obtain the results.
SQL_ID 57s100mh142wy, child number 0
-------------------------------------
SELECT COUNT (*) FROM sales s, customers c WHERE c.cust_id = s.cust_id AND c.cust_city =
'Smithville'
--------------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost (%CPU)| Time|Pstart|Pstop|
--------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |29 (100)| | | |
| 1| SORT AGGREGATE | | 1 | 5| | | | |
| 2| PARTITION RANGE ALL | | 1708|8540|29 (0)| 00:00:01 | 1 | 28 |
| 3| BITMAP CONVERSION COUNT | | 1708|8540|29 (0)| 00:00:01 | | |
|*4| BITMAP INDEX SINGLE VALUE| CUST_SALES_BJI | | | | | 1 | 28 |
--------------------------------------------------------------------------------------------
4 - access("S"."SYS_NC00008$"='Smithville')
See Also:
Oracle Database Concepts to learn about the CREATE INDEX statement
Bitmap Storage
A bitmap index resides in a B-tree structure, using branch blocks and leaf blocks just
as in a B-tree. For example, if the customers.cust_marital_status column has
12 distinct values, then one branch block might point to the keys married,rowid-
range and single,rowid-range, another branch block might point to the
The following plan shows that the database uses a range scan to find all key values
less than 1918 (Step 3), converts the 1 values in the bitmap to rowids (Step 2), and
then uses the rowids to obtain the rows from the customers table (Step 1):
---------------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |421 (100)| |
| 1| TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS |3604|68476|421 (1)| 00:00:01 |
| 2| BITMAP CONVERSION TO ROWIDS | | | | | |
|*3| BITMAP INDEX RANGE SCAN | CUSTOMERS_YOB_BIX| | | | |
---------------------------------------------------------------------------------------------
The following plan shows that the database reads the entry with the Widowed key in
the customers bitmap index (Step 3), converts the 1 values in the bitmap to rowids
(Step 2), and then uses the rowids to obtain the rows from the customers table (Step
1):
SQL_ID ff5an2xsn086h, child number 0
-------------------------------------
SELECT * FROM customers WHERE cust_marital_status = 'Widowed'
3 - access("CUST_MARITAL_STATUS"='Widowed')
The following plan shows that the database obtains all bitmaps for
cust_year_of_birth keys lower than 1918 (Step 3), converts the bitmaps to
rowids (Step 2), and then fetches the rows (Step 1):
SQL_ID 672z2h9rawyjg, child number 0
-------------------------------------
SELECT cust_last_name, cust_first_name FROM customers WHERE
cust_year_of_birth < 1918
Bitmap Merge
This access path merges multiple bitmaps together, and returns a single bitmap as a
result.
The following plan shows that the database obtains all bitmaps for
cust_year_of_birth keys lower than 1918 (Step 6), and then merges these
bitmaps to create a single bitmap (Step 5), obtains a single bitmap for the
cust_gender key of F (Step 4), and then performs an AND operation on these two
bitmaps to generate a single bitmap that contains 1 values for the desired rows (Step
3):
SQL_ID 1xf59h179zdg2, child number 0
-------------------------------------
select cust_last_name, cust_first_name from customers where cust_gender
= 'F' and cust_year_of_birth < 1918
Cluster Scans
An index cluster is a table cluster that uses an index to locate data. The cluster index is
a B-tree index on the cluster key. A cluster scan retrieves all rows that have the same
cluster key value from a table stored in an indexed cluster.
The B-tree cluster index associates the cluster key value with the database block
address (DBA) of the block containing the data. For example, the index entry for key
30 shows the address of the block that contains rows for employees in department 30:
30,AADAAAA9d
When a user requests rows in the cluster, the database scans the index to obtain the
DBAs of the blocks containing the rows. Oracle Database then locates the rows based
on these DBAs.
To perform the scan, Oracle Database first obtains the rowid of the row describing
department 30 by scanning the cluster index (Step 2). Oracle Database then locates the
rows in employees using this rowid (Step 1).
SQL_ID b7xk1jzuwdc6t, child number 0
-------------------------------------
SELECT * FROM employees2 WHERE department_id = 30
--------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)| Time |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 2 (100)| |
| 1| TABLE ACCESS CLUSTER| EMPLOYEES2 | 6 | 798 | 2 (0)| 00:00:01|
|*2| INDEX UNIQUE SCAN |IDX_EMP_DEPT_CLUSTER| 1 | | 1 (0)| 00:00:01|
--------------------------------------------------------------------------------
2 - access("DEPARTMENT_ID"=30)
See Also:
Oracle Database Concepts to learn about indexed clusters
Hash Scans
A hash cluster is like an indexed cluster, except the index key is replaced with a hash
function. No separate cluster index exists. In a hash cluster, the data is the index. The
database uses a hash scan to locate rows in a hash cluster based on a hash value.
To perform a hash scan, Oracle Database first obtains the hash value by applying a
hash function to the key value 30, and then uses this hash value to scan the data
blocks and retrieve the rows (Step 1).
SQL_ID 919x7hyyxr6p4, child number 0
-------------------------------------
SELECT * FROM employees2 WHERE department_id = 30
----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1 |
|* 1 | TABLE ACCESS HASH| EMPLOYEES2 | 10 | 1330 | |
----------------------------------------------------------------
1 - access("DEPARTMENT_ID"=30)
See Also:
• About Joins
• Join Methods
• Join Types
• Join Optimizations
About Joins
A join combines the output from exactly two row sources, such as tables or views, and
returns one row source. The returned row source is the data set.
A join is characterized by multiple tables in the WHERE (non-ANSI) or FROM ...
JOIN (ANSI) clause of a SQL statement. Whenever multiple tables exist in the FROM
clause, Oracle Database performs a join.
A join condition compares two row sources using an expression. The join condition
defines the relationship between the tables. If the statement does not specify a join
condition, then the database performs a Cartesian join (see “Cartesian Joins”),
matching every row in one table with every row in the other table.
See Also:
Join Trees
Typically, a join tree is represented as an upside-down tree structure. As shown in
Figure 9-1, table1 is the left table, and table2 is the right table. The optimizer
processes the join from left to right. For example, if this graphic depicted a nested
loops join, then table1 is the outer loop, and table2 is the inner loop.
Joins 9-1
About Joins
table1 table2
The input of a join can be the result set from a previous join. If a join tree includes
more than two branches, then the most common tree type is the left deep tree, which is
illustrated in Figure 9-2. A left deep tree is a join tree in which every join has an input
from a previous join, and this input is always on the left.
table4
table3
table1 table2
A less common type of join tree is a right join tree, shown in Figure 9-3, in which every
join has an input from a previous join, and this input is always on the right.
table1
table2
table3 table4
Some join trees are hybrids of left and right trees, so that some joins have a right input
from a previous join, and some joins have a left input from a previous join. Figure 9-4
gives an example of this type of tree.
result set
table4
table1
table2 table3
In yet another variation, both inputs of the join are the results of a previous join.
• Access paths
As for simple statements, the optimizer must choose an access path to retrieve data
from each table in the join statement. For example, the optimizer might choose
between a full table scan or an index scan. See Optimizer Access Paths .
• Join methods
To join each pair of row sources, Oracle Database must decide how to do it. The
"how" is the join method. The possible join methods are nested loop, sort merge,
and hash joins. A Cartesian join requires one of the preceding join methods. Each
join method has specific situations in which it is more suitable than the others. See
“Join Methods.”
• Join types
The join condition determines the join type. For example, an inner join retrieves
only rows that match the join condition. An outer join retrieves rows that do not
match the join condition. See “Join Types.”
• Join order
To execute a statement that joins more than two tables, Oracle Database joins two
tables and then joins the resulting row source to the next table. This process
continues until all tables are joined into the result. For example, the database joins
two tables, and then joins the result to a third table, and then joins this result to a
fourth table, and so on.
Joins 9-3
About Joins
orders, join methods, and available access paths. The optimizer then estimates the cost
of each plan and chooses the one with the lowest cost.
When choosing an execution plan, the optimizer considers the following factors:
• The optimizer first determines whether joining two or more tables results in a row
source containing at most one row.
The optimizer recognizes such situations based on UNIQUE and PRIMARY KEY
constraints on the tables. If such a situation exists, then the optimizer places these
tables first in the join order. The optimizer then optimizes the join of the remaining
set of tables.
• For join statements with outer join conditions, the table with the outer join operator
typically comes after the other table in the condition in the join order.
In general, the optimizer does not consider join orders that violate this guideline,
although the optimizer overrides this ordering condition in certain circumstances.
Similarly, when a subquery has been converted into an antijoin or semijoin, the
tables from the subquery must come after those tables in the outer query block to
which they were connected or correlated. However, hash antijoins and semijoins
are able to override this ordering condition in certain circumstances.
The optimizer estimates cost of a query plan by computing the estimated I/Os and
CPU. These I/Os have specific costs associated with them: one cost for a single block
I/O, and another cost for multiblock I/Os. Also, different functions and expressions
have CPU costs associated with them. The optimizer determines the total cost of a
query plan using these metrics. These metrics may be influenced by many
initialization parameter and session settings at compile time, such as the
DB_FILE_MULTI_BLOCK_READ_COUNT setting, system statistics, and so on.
For example, the optimizer estimates costs in the following ways:
• The cost of a nested loops join depends on the cost of reading each selected row of
the outer table and each of its matching rows of the inner table into memory. The
optimizer estimates these costs using statistics in the data dictionary (see
“Introduction to Optimizer Statistics”).
• The cost of a sort merge join depends largely on the cost of reading all the sources
into memory and sorting them.
• The cost of a hash join largely depends on the cost of building a hash table on one
of the input sides to the join and using the rows from the other side of the join to
probe it.
See Also:
variations of methods and orders, and the cost for each. In this example, a nested loops
join in the order date_dim, lineorder has the lowest cost.
Table 9-1 Sample Costs for Join of date_dim and lineorder Tables
Join Methods
A join method is the mechanism for joining two row sources. Depending on the
statistics, the optimizer chooses the method with the lowest estimated cost.
As shown in Figure 9-5, each join method has two children: the driving (also called
outer) row source and the driven-to (also called inner) row source.
Join Method
(Nested Loops, Hash
Join, or Sort Merge)
• Hash Joins
• Cartesian Joins
Joins 9-5
Join Methods
• The database joins small subsets of data, or the database joins large sets of data
with the optimizer mode set to FIRST_ROWS (see Table 14-1).
Note:
The number of rows expected from the join is what drives the optimizer
decision, not the size of the underlying tables. For example, a query might join
two tables of a billion rows each, but because of the filters the optimizer
expects data sets of 5 rows each.
The inner loop is executed for every row of the outer loop. The employees table is the
"outer" data set because it is in the exterior for loop. The outer table is sometimes
called a driving table. The departments table is the "inner" data set because it is in
the interior for loop.
A nested loops join involves the following basic steps:
1. The optimizer determines the driving row source and designates it as the outer
loop.
The outer loop produces a set of rows for driving the join condition. The row
source can be a table accessed using an index scan, a full table scan, or any other
operation that generates rows.
The number of iterations of the inner loop depends on the number of rows
retrieved in the outer loop. For example, if 10 rows are retrieved from the outer
table, then the database must perform 10 lookups in the inner table. If 10,000,000
rows are retrieved from the outer table, then the database must perform
10,000,000 lookups in the inner table.
2. The optimizer designates the other row source as the inner loop.
The outer loop appears before the inner loop in the execution plan, as follows:
NESTED LOOPS
outer_loop
inner_loop
3. For every fetch request from the client, the basic process is as follows:
b. Probe the inner row source to find rows that match the predicate criteria
c. Repeat the preceding steps until all rows are obtained by the fetch request
Sometimes the database sorts rowids to obtain a more efficient buffer access
pattern.
Joins 9-7
Join Methods
2. The database iterates through NESTED LOOPS 2, using the row source generated
by NESTED LOOPS 1 as its outer loop:
NESTED LOOPS 2
OUTER LOOP 2.1 - Row source generated by NESTED LOOPS 1
INNER LOOP 2.2
3. The database iterates through NESTED LOOPS 3, using the row source generated
by NESTED LOOPS 2 as its outer loop:
NESTED LOOPS 3
OUTER LOOP 3.1 - Row source generated by NESTED LOOPS 2
INNER LOOP 3.2
The plan reveals that the optimizer chose two nested loops (Step 1 and Step 2) to
access the data:
SQL_ID ahuavfcv4tnz4, child number 0
-------------------------------------
SELECT /*+ ORDERED USE_NL(d) */ e.last_name, d.department_name FROM
employees e, departments d WHERE e.department_id=d.department_id AND
e.last_name like 'A%'
----------------------------------------------------------------------------------
|Id| Operation |Name |Rows|Bytes|Cost(%CPU)|Time|
----------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |5 (100)| |
| 1| NESTED LOOPS | | | | | |
| 2| NESTED LOOPS | | 3|102|5 (0)|00:00:01|
| 3| TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 3| 54|2 (0)|00:00:01|
|*4| INDEX RANGE SCAN | EMP_NAME_IX | 3| |1 (0)|00:00:01|
|*5| INDEX UNIQUE SCAN | DEPT_ID_PK | 1| |0 (0)| |
| 6| TABLE ACCESS BY INDEX ROWID | DEPARTMENTS | 1| 16|1 (0)|00:00:01|
----------------------------------------------------------------------------------
1. The database begins iterating through the inner nested loop (Step 2) as follows:
a. The database searches the emp_name_ix for the rowids for all last names that
begins with A (Step 4).
For example:
Abel,employees_rowid
Ande,employees_rowid
Atkinson,employees_rowid
Austin,employees_rowid
b. Using the rowids from the previous step, the database retrieves a batch of
rows from the employees table (Step 3). For example:
Abel,Ellen,80
Abel,John,50
These rows become the outer row source for the innermost nested loop.
The batch step is typically part of adaptive execution plans. To determine
whether a nested loop is better than a hash join, the optimizer needs to
determine many rows come back from the row source. If too many rows are
returned, then the optimizer switches to a different join method.
c. For each row in the outer row source, the database scans the dept_id_pk
index to obtain the rowid in departments of the matching department ID
(Step 5), and joins it to the employees rows. For example:
Abel,Ellen,80,departments_rowid
Ande,Sundar,80,departments_rowid
Atkinson,Mozhe,50,departments_rowid
Austin,David,60,departments_rowid
These rows become the outer row source for the outer nested loop (Step 1).
c. The database reads the next row in the outer row source, uses the
departments rowid to retrieve the corresponding row from departments
(Step 6), and iterates through the loop until all rows are retrieved.
The result set has the following form:
Abel,Ellen,80,Sales
Ande,Sundar,80,Sales
Atkinson,Mozhe,50,Shipping
Austin,David,60,IT
Joins 9-9
Join Methods
one at a time. A vector is an array. The database obtains a set of rowids, and then
sends them in an array to the operating system, which performs the read.
As part of the new implementation, two NESTED LOOPS join row sources might
appear in the execution plan where only one would have appeared in prior releases. In
such cases, Oracle Database allocates one NESTED LOOPS join row source to join the
values from the table on the outer side of the join with the index on the inner side. A
second row source is allocated to join the result of the first join, which includes the
rowids stored in the index, with the table on the inner side of the join.
Consider the query in “Original Implementation for Nested Loops Joins”. In the
current implementation, the execution plan for this query might be as follows:
-------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost%CPU| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 19 | 722 | 3 (0)|00:00:01|
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 19 | 722 | 3 (0)|00:00:01|
|* 3 | TABLE ACCESS FULL | DEPARTMENTS | 2 | 32 | 2 (0)|00:00:01|
|* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 10 | | 0 (0)|00:00:01|
| 5 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 10 | 220 | 1 (0)|00:00:01|
-------------------------------------------------------------------------------------
In this case, rows from the hr.departments table form the outer row source (Step 3)
of the inner nested loop (Step 2). The index emp_department_ix is the inner row
source (Step 4) of the inner nested loop. The results of the inner nested loop form the
outer row source (Row 2) of the outer nested loop (Row 1). The hr.employees table
is the outer row source (Row 5) of the outer nested loop.
For each fetch request, the basic process is as follows:
1. The database iterates through the inner nested loop (Step 2) to obtain the rows
requested in the fetch:
a. The database reads the first row of departments to obtain the department
IDs for departments named Marketing or Sales (Step 3). For example:
Marketing,20
This row set is the outer loop. The database caches the data in the PGA.
In this example, the database only iterates through the outer loop twice
because only two rows from departments satisfy the predicate filter.
Conceptually, the result set has the following form:
Marketing,20,employees_rowid
Marketing,20,employees_rowid
Marketing,20,employees_rowid
.
.
.
Sales,80,employees_rowid
Sales,80,employees_rowid
Sales,80,employees_rowid
.
.
.
These rows become the outer row source for the outer nested loop (Step 1).
This row set is cached in the PGA.
2. The database organizes the rowids obtained in the previous step so that it can
more efficiently access them in the cache.
3. The database begins iterating through the outer nested loop as follows:
a. The database retrieves the first row from the row set obtained in the previous
step, as in the following example:
Marketing,20,employees_rowid
b. Using the rowid, the database retrieves a row from employees to obtain the
requested values (Step 1), as in the following example:
Michael,Hartstein,13000,Marketing
c. The database retrieves the next row from the row set, uses the rowid to probe
employees for the matching row, and iterates through the loop until all rows
are retrieved.
The result set has the following form:
Michael,Hartstein,13000,Marketing
Pat,Fay,6000,Marketing
John,Russell,14000,Sales
Karen,Partners,13500,Sales
Alberto,Errazuriz,12000,Sales
.
.
.
In some cases, a second join row source is not allocated, and the execution plan looks
the same as it did before Oracle Database 11g. The following list describes such cases:
• All of the columns needed from the inner side of the join are present in the index,
and there is no table access required. In this case, Oracle Database allocates only
one join row source.
• The order of the rows returned might be different from the order returned in
releases earlier than Oracle Database 12c. Thus, when Oracle Database tries to
preserve a specific ordering of the rows, for example to eliminate the need for an
ORDER BY sort, Oracle Database might use the original implementation for nested
loops joins.
Joins 9-11
Join Methods
In releases before Oracle Database 11g, the execution plan for this query might appear
as follows:
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 19 | 722 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 10 | 220 | 1 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 19 | 722 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | DEPARTMENTS | 2 | 32 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 10 | | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
1. The database iterates through the loop to obtain the rows requested in the fetch:
a. The database reads the first row of departments to obtain the department
IDs for departments named Marketing or Sales (Step 3). For example:
Marketing,20
This row set is the outer loop. The database caches the row in the PGA.
Marketing,20,employees_rowid
Marketing,20,employees_rowid
Marketing,20,employees_rowid
.
.
.
Sales,80,employees_rowid
Sales,80,employees_rowid
Sales,80,employees_rowid
.
.
.
2. Depending on the circumstances, the database may organize the cached rowids
obtained in the previous step so that it can more efficiently access them.
3. For each employees rowid in the result set generated by the nested loop, the
database retrieves a row from employees to obtain the requested values (Step 1).
Thus, the basic process is to read a rowid and retrieve the matching employees
row, read the next rowid and retrieve the matching employees row, and so on.
Conceptually, the result set has the following form:
Michael,Hartstein,13000,Marketing
Pat,Fay,6000,Marketing
John,Russell,14000,Sales
Karen,Partners,13500,Sales
Alberto,Errazuriz,12000,Sales
.
.
.
Joins 9-13
Join Methods
To force a nested loops join using departments as the inner table, add the USE_NL
hint as in the following query:
SELECT /*+ ORDERED USE_NL(d) */ e.last_name, d.department_name
FROM employees e, departments d
WHERE e.department_id=d.department_id;
3 - filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
1. In the nested loop, the database reads employees to obtain the last name and
department ID for an employee (Step 2). For example:
De Haan,90
2. For the row obtained in the previous step, the database scans departments to
find the department name that matches the employees department ID (Step 3),
and joins the result (Step 1). For example:
De Haan,Executive
3. The database retrieves the next row in employees, retrieves the matching row
from departments, and then repeats this process until all rows are retrieved.
The result set has the following form:
De Haan,Executive
Kochnar,Executive
Baer,Public Relations
King,Executive
.
.
.
See Also:
• “Guidelines for Join Order Hints” to learn more about the USE_NL hint
• Oracle Database SQL Language Reference to learn about the USE_NL hint
Hash Joins
The database uses a hash join to join larger data sets. The optimizer uses the smaller
of two data sets to build a hash table on the join key in memory, using a deterministic
hash function to specify the location in the hash table in which to store each row. The
database then scans the larger data set, probing the hash table to find the rows that
meet the join condition.
• A relatively large amount of data must be joined, or a large fraction of a small table
must be joined.
Hash Tables
To illustrate a hash table, assume that the database hashes hr.departments in a join
of departments and employees. The join key column is department_id. The first
5 rows of departments are as follows:
SQL> select * from departments where rownum < 6;
The database applies the hash function to each department_id in the table,
generating a hash value for each. For this illustration, the hash table has 5 slots (it
could have more or less). Because n is 5, the possible hash values range from 1 to 5.
The hash functions might generate the following values for the department IDs:
f(10) = 4
f(20) = 1
f(30) = 4
Joins 9-15
Join Methods
f(40) = 2
f(50) = 5
Note that the hash function happens to generate the same hash value of 4 for
departments 10 and 30. This is known as a hash collision. In this case, the database
puts the records for departments 10 and 30 in the same slot, using a linked list.
Conceptually, the hash table looks as follows:
1 20,Marketing,201,1800
2 40,Human Resources,203,2400
3
4 10,Administration,200,1700 -> 30,Purchasing,114,1700
5 50,Shipping,121,1500
1. The database performs a full scan of the smaller data set, called the build table,
and then applies a hash function to the join key in each row to build a hash table
in the PGA.
In pseudocode, the algorithm might look as follows:
FOR small_table_row IN (SELECT * FROM small_table)
LOOP
slot_number := HASH(small_table_row.join_key);
INSERT_HASH_TABLE(slot_number,small_table_row);
END LOOP;
2. The database probes the second data set, called the probe table, using whichever
access mechanism has the lowest cost.
Typically, the database performs a full scan of both the smaller and larger data set.
The algorithm in pseudocode might look as follows:
FOR large_table_row IN (SELECT * FROM large_table)
LOOP
slot_number := HASH(large_table_row.join_key);
small_table_row = LOOKUP_HASH_TABLE(slot_number,large_table_row.join_key);
IF small_table_row FOUND
THEN
output small_table_row + large_table_row;
END IF;
END LOOP;
For each row retrieved from the larger data set, the database does the following:
a. Applies the same hash function to the join column or columns to calculate the
number of the relevant slot in the hash table.
For example, to probe the hash table for department ID 30, the database
applies the hash function to 30, which generates the hash value 4.
b. Probes the hash table to determine whether rows exists in the slot.
If no rows exist, then the database processes the next row in the larger data
set. If rows exist, then the database proceeds to the next step.
c. Checks the join column or columns for a match. If a match occurs, then the
database either reports the rows or passes them to the next step in the plan,
and then processes the next row in the larger data set.
If multiple rows exist in the hash table slot, the database walks through the
linked list of rows, checking each one. For example, if department 30 hashes
to slot 4, then the database checks each row until it finds 30.
Example 9-4 Hash Joins
An application queries the oe.orders and oe.order_items tables, joining on the
order_id column.
SELECT o.customer_id, l.unit_price * l.quantity
FROM orders o, order_items l
WHERE l.order_id = o.order_id;
Because the orders table is small relative to the order_items table, which is 6 times
larger, the database hashes orders. In a hash join, the data set for the build table
always appears first in the list of operations (Step 2). In Step 3, the database performs a
full scan of the larger order_items later, probing the hash table for each row.
How Hash Joins Work When the Hash Table Does Not Fit in the PGA
The database must use a different technique when the hash table does not fit entirely
in the PGA. In this case, the database uses a temporary space to hold portions (called
partitions) of the hash table, and sometimes portions of the larger table that probes the
hash table.
The basic process is as follows:
1. The database performs a full scan of the smaller data set, and then builds an array
of hash buckets in both the PGA and on disk.
When the PGA hash area fills up, the database finds the largest partition within
the hash table and writes it to temporary space on disk. The database stores any
new row that belongs to this on-disk partition on disk, and all other rows in the
PGA. Thus, part of the hash table is in memory and part of it on disk.
2. The database takes a first pass at reading the other data set.
For each row, the database does the following:
a. Applies the same hash function to the join column or columns to calculate the
number of the relevant hash bucket.
b. Probes the hash table to determine whether rows exist in the bucket in
memory.
Joins 9-17
Join Methods
If the hashed value points to a row in memory, then the database completes
the join and returns the row. If the value points to a hash partition on disk,
however, then the database stores this row in the temporary tablespace, using
the same partitioning scheme used for the original data set.
4. The database joins each partition row to the row in the corresponding on-disk
temporary partition.
MERGE JOIN
• The join condition between two tables is not an equijoin, that is, uses an inequality
condition such as <, <=, >, or >=.
In contrast to sort merges, hash joins require an equality condition.
• Because of sorts required by other operations, the optimizer finds it cheaper to use
a sort merge.
If an index exists, then the database can avoid sorting the first data set. However,
the database always sorts the second data set, regardless of indexes.
A sort merge has the same advantage over a nested loops join as the hash join: the
database accesses rows in the PGA rather than the SGA, reducing logical I/O by
avoiding the necessity of repeatedly latching and reading blocks in the database buffer
cache. In general, hash joins perform better than sort merge joins because sorting is
expensive. However, sort merge joins offer the following advantages over a hash join:
• After the initial sort, the merge phase is optimized, resulting in faster generation of
output rows.
• A sort merge can be more cost-effective than a hash join when the hash table does
not fit completely in memory.
A hash join with insufficient memory requires both the hash table and the other
data set to be copied to disk. In this case, the database may have to read from disk
multiple times. In a sort merge, if memory cannot hold the two data sets, then the
database writes them both to disk, but reads each data set no more than once.
For example, the database sorts the first data set as follows:
10,20,30,40,50,60,70
The database begins by reading 10 in the first data set, and then starts at the beginning
of data set 2:
20 too high, stop, get next ds1_row
The database proceeds to the second row of data set 1 (20). The database proceeds
through the second data set as follows:
20 match, proceed
20 match, proceed
40 too high, stop, get next ds1_row
The database gets the next row in data set 1, which is 30. The database starts at the
number of its last match, which was 20, and then walks through data set 2 looking for
a match:
Joins 9-19
Join Methods
The database gets the next row in data set 1, which is 40. The database starts at the
number of its last match, which was 20, and then proceeds through data set 2 looking
for a match:
20 too low, proceed
20 too low, proceed
40 match, proceed
40 match, proceed
40 match, proceed
40 match, proceed
40 match, proceed
60 too high, stop, get next ds1_row
As the database proceeds through data set 1, the database does not need to read every
row in data set 2. This is an advantage over a nested loops join.
Example 9-5 Sort Merge Join Using Index
The following query joins the employees and departments tables on the
department_id column, ordering the rows on department_id as follows:
SELECT e.employee_id, e.last_name, e.first_name, e.department_id,
d.department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id
ORDER BY department_id;
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
The two data sets are the departments table and the employees table. Because an
index orders the departments table by department_id, the database can read this
index and avoid a sort (Step 3). The database only needs to sort the employees table
(Step 4), which is the most CPU-intensive operation.
Example 9-6 Sort Merge Join Without an Index
You join the employees and departments tables on the department_id column,
ordering the rows on department_id as follows. In this example, you specify
NO_INDEX and USE_MERGE to force the optimizer to choose a sort merge:
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
See Also:
Oracle Database SQL Language Reference to learn about the USE_MERGE hint
Cartesian Joins
The database uses a Cartesian join when one or more of the tables does not have any
join conditions to any other tables in the statement. The optimizer joins every row
from one data source with every row from the other data source, creating the
Cartesian product of the two sets. Therefore, the total number of rows resulting from
the join is calculated using the following formula, where rs1 is the number of rows in
first row set and rs2 is the number of rows in the second row set:
rs1 X rs2 = total rows in result set
Joins 9-21
Join Methods
Note:
• The ORDERED hint specifies a table before its join table is specified.
In Step 1 of the preceding plan, the CARTESIAN keyword indicates the presence of a
Cartesian join. The number of rows (2889) is the product of 27 and 107.
In Step 3, the BUFFER SORT operation indicates that the database is copying the data
blocks obtained by the scan of emp_name_ix from the SGA to the PGA. This strategy
avoids multiple scans of the same blocks in the database buffer cache, which would
generate many logical reads and permit resource contention.
See Also:
Oracle Database SQL Language Reference to learn about the ORDERED hint
The following execution plan shows a Cartesian product (Step 3) between locations
(Step 6) and employees (Step 4), which is then joined to the departments table
(Step 2):
--------------------------------------------------------------------------------
| Id| Operation | Name | Rows | Bytes |Cost (%CPU)|Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 37 (100)| |
|*1 | HASH JOIN | | 106 | 4664 | 37 (6)| 00:00:01 |
| 2 | TABLE ACCESS FULL | DEPARTMENTS | 27 | 513 | 2 (0)| 00:00:01 |
| 3 | MERGE JOIN CARTESIAN| | 2461 | 61525 | 34 (3)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMPLOYEES | 107 | 1177 | 2 (0)| 00:00:01 |
| 5 | BUFFER SORT | | 23 | 322 | 32 (4)| 00:00:01 |
| 6 | TABLE ACCESS FULL | LOCATIONS | 23 | 322 | 0 (0)| |
--------------------------------------------------------------------------------
Join Types
A join type is determined by the type of join condition. This section contains the
following topics:
• Inner Joins
• Outer Joins
• Semijoins
• Antijoins
Inner Joins
An inner join (sometimes called a simple join) is a join that returns only rows that
satisfy the join condition. Inner joins are either equijoins or nonequijoins.
Joins 9-23
Join Types
Equijoins
An equijoin is an inner join whose join condition contains an equality operator. The
following example is an equijoin because the join condition contains only an equality
operator:
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e, departments d
WHERE e.department_id=d.department_id;
Nonequijoins
A nonequijoin is an inner join whose join condition contains an operator that is not an
equality operator. The following query lists all employees whose hire date occurred
when employee 176 (who is listed in job_history because he changed jobs in 2007)
was working at the company:
SELECT e.employee_id, e.first_name, e.last_name, e.hire_date
FROM employees e, job_history h
WHERE h.employee_id = 176
AND e.hire_date BETWEEN h.start_date AND h.end_date;
In the preceding example, the condition joining employees and job_history does
not contain an equality operator, so it is a nonequijoin. Nonequijoins are relatively
rare.
Note that a hash join requires at least a partial equijoin. The following SQL script
contains an equality join condition (e1.empno = e2.empno) and a nonequality
condition:
SET AUTOTRACE TRACEONLY EXPLAIN
SELECT *
FROM scott.emp e1 JOIN scott.emp e2
ON ( e1.empno = e2.empno
AND e1.hiredate BETWEEN e2.hiredate-1 AND e2.hiredate+1 )
The optimizer chooses a hash join for the preceding query, as shown in the following
plan:
Execution Plan
----------------------------------------------------------
Plan hash value: 3638257876
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 174 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN | | 1 | 174 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 14 | 1218 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 14 | 1218 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------
1 - access("E1"."EMPNO"="E2"."EMPNO")
filter("E1"."HIREDATE">=INTERNAL_FUNCTION("E2"."HIREDATE")-1 AND
"E1"."HIREDATE"<=INTERNAL_FUNCTION("E2"."HIREDATE")+1)
Outer Joins
An outer join returns all rows that satisfy the join condition and also returns some or
all of those rows from one table for which no rows from the other satisfy the join
condition. Thus, an outer join extends the result of a simple join.
In ANSI syntax, the OUTER JOIN clause specifies an outer join. In the FROM clause, the
left table appears to the left of the OUTER JOIN keywords, and the right table
appears to the right of these keywords. The left table is also called the outer table, and
the right table is also called the inner table. For example, in the following statement the
employees table is the left or outer table:
SELECT employee_id, last_name, first_name
FROM employees LEFT OUTER JOIN departments
ON (employees.department_id=departments.departments_id);
Outer joins require the outer joined table to be the driving table. In the preceding
example, employees is the driving table, and departments is the driven-to table.
This section contains the following topics:
• Data volume is low enough to make the nested loop method efficient.
For an example of a nested loop outer join, you can add the USE_NL hint to Example
9-9 to instruct the optimizer to use a nested loop. For example:
SELECT /*+ USE_NL(c o) */ cust_last_name,
SUM(NVL2(o.customer_id,0,1)) "Count"
FROM customers c, orders o
WHERE c.credit_limit > 1000
AND c.customer_id = o.customer_id(+)
GROUP BY cust_last_name;
Joins 9-25
Join Types
• The data volume is large enough to make the hash join method efficient.
• It is not possible to drive from the outer table to the inner table.
The cost determines the order of tables. The outer table, including preserved rows,
may be used to build the hash table, or it may be used to probe the hash table.
Example 9-9 Hash Join Outer Joins
This example shows a typical hash join outer join query, and its execution plan. In this
example, all the customers with credit limits greater than 1000 are queried. An outer
join is needed so that the query captures customers who have no orders.
• The join preserves the customers rows, including those rows without a
corresponding row in orders.
You could use a NOT EXISTS subquery to return the rows. However, because you are
querying all the rows in the table, the hash join performs better (unless the NOT
EXISTS subquery is not nested).
SELECT cust_last_name, SUM(NVL2(o.customer_id,0,1)) "Count"
FROM customers c, orders o
WHERE c.credit_limit > 1000
AND c.customer_id = o.customer_id(+)
GROUP BY cust_last_name;
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 7 (100)| |
| 1 | HASH GROUP BY | | 168 | 3192 | 7 (29)| 00:00:01 |
|* 2 | HASH JOIN OUTER | | 318 | 6042 | 6 (17)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| CUSTOMERS | 260 | 3900 | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| ORDERS | 105 | 420 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------
2 - access("C"."CUSTOMER_ID"="O"."CUSTOMER_ID")
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
3 - filter("C"."CREDIT_LIMIT">1000)
4 - filter("O"."CUSTOMER_ID">0)
The query looks for customers which satisfy various conditions. An outer join returns
NULL for the inner table columns along with the outer (preserved) table rows when it
does not find any corresponding rows in the inner table. This operation finds all the
customers rows that do not have any orders rows.
In this case, the outer join condition is the following:
customers.customer_id = orders.customer_id(+)
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 144 | 4608 | 16 (32)|
| 1 | HASH GROUP BY | | 144 | 4608 | 16 (32)|
|* 2 | HASH JOIN OUTER | | 663 | 21216 | 15 (27)|
|* 3 | TABLE ACCESS FULL | CUSTOMERS | 195 | 2925 | 6 (17)|
| 4 | VIEW | V_ORDERS | 665 | 11305 | |
| 5 | HASH GROUP BY | | 665 | 15960 | 9 (34)|
|* 6 | HASH JOIN | | 665 | 15960 | 8 (25)|
|* 7 | TABLE ACCESS FULL| ORDERS | 105 | 840 | 4 (25)|
| 8 | TABLE ACCESS FULL| ORDER_ITEMS | 665 | 10640 | 4 (25)|
----------------------------------------------------------------------------
• A nested loops join is inefficient. A nested loops join can be inefficient because of
data volumes.
Joins 9-27
Join Types
• The optimizer finds it is cheaper to use a sort merge over a hash join because of
sorts required by other operations.
---------------------------------------------------
3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
HASH JOIN FULL OUTER is included in the preceding plan (Step 3), indicating that the
query uses the hash full outer join execution method. Typically, when the full outer
join condition between two tables is an equijoin, the hash full outer join execution
method is possible, and Oracle Database uses it automatically.
To instruct the optimizer to consider using the hash full outer join execution method,
apply the NATIVE_FULL_OUTER_JOIN hint. To instruct the optimizer not to consider
using the hash full outer join execution method, apply the
NO_NATIVE_FULL_OUTER_JOIN hint. The NO_NATIVE_FULL_OUTER_JOIN hint
instructs the optimizer to exclude the native execution method when joining each
specified table. Instead, the full outer join is executed as a union of left outer join and
an antijoin.
Semijoins
A semijoin is a join between two data sets that returns a row from the first set when a
matching row exists in the subquery data set. The database stops processing the
second data set at the first match. Thus, optimization does not duplicate rows from the
first data set when multiple rows in the second data set satisfy the subquery criteria.
Note:
Semijoins and antijoins are considered join types even though the SQL
constructs that cause them are subqueries. They are internal algorithms that
the optimizer uses to flatten subquery constructs so that they can be resolved
in a join-like way.
Joins 9-29
Join Types
In the preceding pseudocode, ds1 is the first data set, and ds2_subquery is the
subquery data set. The code obtains the first row from the first data set, and then loops
through the subquery data set looking for a match. The code exits the inner loop as
soon as it finds a match, and then begins processing the next row in the first data set.
Example 9-13 Semijoin Using WHERE EXISTS
The following query uses a WHERE EXISTS clause to list only the departments that
contain employees:
SELECT department_id, department_name
FROM departments
WHERE EXISTS (SELECT 1
FROM employees
WHERE employees.department_id = departments.department_id)
For each row in departments, which forms the outer loop, the database obtains the
department ID, and then probes the employees.department_id index for
matching entries. Conceptually, the index looks as follows:
10,rowid
10,rowid
10,rowid
10,rowid
30,rowid
30,rowid
30,rowid
...
If the first entry in the departments table is department 30, then the database
performs a range scan of the index until it finds the first 30 entry, at which point it
stops reading the index and returns the matching row from departments. If the next
row in the outer loop is department 20, then the database scans the index for a 20
entry, and not finding any matches, performs the next iteration of the outer loop. The
database proceeds in this way until all matching rows are returned.
Example 9-14 Semijoin Using IN
The following query uses a IN clause to list only the departments that contain
employees:
SELECT department_id, department_name
FROM departments
WHERE department_id IN
(SELECT department_id
FROM employees);
Antijoins
An antijoin is a join between two data sets that returns a row from the first set when a
matching row does not exist in the subquery data set. Like a semijoin, an antijoin stops
processing the subquery data set when the first match is found. Unlike a semijoin, the
antijoin only returns a row when no match is found.
• The statement performs an outer join and applies an IS NULL condition to a join
column, as in the following example:
SET AUTOTRACE TRACEONLY EXPLAIN
SELECT emp.*
FROM emp, dept
WHERE emp.deptno = dept.deptno(+)
Joins 9-31
Join Types
Execution Plan
----------------------------------------------------------
Plan hash value: 1543991079
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 1400 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN ANTI | | 14 | 1400 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 14 | 1218 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| DEPT | 4 | 52 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------
1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
In the preceding pseudocode, ds1 is the first data set, and ds2 is the second data set.
The code obtains the first row from the first data set, and then loops through the
second data set looking for a match. The code exits the inner loop as soon as it finds a
match, and begins processing the next row in the first data set.
Example 9-15 Semijoin Using WHERE EXISTS
The following query uses a WHERE EXISTS clause to list only the departments that
contain employees:
SELECT department_id, department_name
FROM departments
WHERE EXISTS (SELECT 1
FROM employees
WHERE employees.department_id = departments.department_id)
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | NESTED LOOPS SEMI | | 11 | 209 | 2 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
|*3 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 44 | 132 | 0 (0)| |
--------------------------------------------------------------------------------
For each row in departments, which forms the outer loop, the database obtains the
department ID, and then probes the employees.department_id index for
matching entries. Conceptually, the index looks as follows:
10,rowid
10,rowid
10,rowid
10,rowid
30,rowid
30,rowid
30,rowid
...
If the first record in the departments table is department 30, then the database
performs a range scan of the index until it finds the first 30 entry, at which point it
stops reading the index and returns the matching row from departments. If the next
row in the outer loop is department 20, then the database scans the index for a 20
entry, and not finding any matches, performs the next iteration of the outer loop. The
database proceeds in this way until all matching rows are returned.
For the entire expression to be true, each individual condition must be true.
However, a null value cannot be compared to another value, so the
department_id !=null condition cannot be true, and thus the whole expression
cannot be true. The following techniques enable a statement to return records even
when nulls are returned to the NOT IN operator:
Joins 9-33
Join Types
In releases earlier than Oracle Database 11g, the optimizer could not use an antijoin
optimization when nulls could be returned by a subquery. However, starting in Oracle
Database 11g, the ANTI NA (and ANTI SNA) optimizations described in the following
sections enable the optimizer to use an antijoin even when nulls are possible.
Example 9-16 Antijoin Using NOT IN
Suppose that a user issues the following query with a NOT IN clause to list the
departments that contain no employees:
SELECT department_id, department_name
FROM departments
WHERE department_id NOT IN
(SELECT department_id
FROM employees);
The preceding query returns no rows even though several departments contain no
employees. This result, which was not intended by the user, occurs because the
employees.department_id column is nullable.
The execution plan reveals a NESTED LOOPS ANTI SNA operation in Step 2:
--------------------------------------------------------------------------------
| Id| Operation | Name |Rows|Bytes|Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 4(100)| |
|*1 | FILTER | | | | | |
| 2 | NESTED LOOPS ANTI SNA| | 17 | 323 | 4 (50)| 00:00:01 |
| 3 | TABLE ACCESS FULL | DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
|*4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 41 | 123 | 0 (0)| |
|*5 | TABLE ACCESS FULL | EMPLOYEES | 1 | 3 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
The ANTI SNA stands for "single null-aware antijoin." ANTI NA stands for "null-
aware antijoin." The null-aware operation enables the optimizer to use the semijoin
optimization even on a nullable column. In releases earlier than Oracle Database 11g,
the database could not perform antijoins on NOT IN queries when nulls were possible.
Suppose that the user rewrites the query by applying an IS NOT NULL condition to
the subquery:
SELECT department_id, department_name
FROM departments
WHERE department_id NOT IN
(SELECT department_id
FROM employees
WHERE department_id IS NOT NULL);
The preceding query returns 16 rows, which is the expected result. Step 1 in the plan
shows a standard NESTED LOOPS ANTI join instead of an ANTI NA or ANTI SNA
join because the subquery cannot returns nulls:
--------------------------------------------------------------------------------
|Id| Operation | Name | Rows| Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 2 (100)| |
| 1| NESTED LOOPS ANTI | | 17 | 323 | 2 (0)| 00:00:01 |
| 2| TABLE ACCESS FULL| DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
|*3| INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 41 | 123 | 0 (0)| |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
filter("DEPARTMENT_ID" IS NOT NULL)
The preceding query avoids the null problem for NOT IN clauses. Thus, even though
employees.department_id column is nullable, the statement returns the desired
result.
Step 1 of the execution plan reveals a NESTED LOOPS ANTI operation, not the ANTI
NA variant, which was necessary for NOT IN when nulls were possible:
--------------------------------------------------------------------------------
| Id| Operation | Name | Rows | Bytes | Cost (%CPU)|Time|
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | NESTED LOOPS ANTI | | 17 | 323 | 2 (0)|00:00:01|
| 2 | TABLE ACCESS FULL| DEPARTMENTS | 27 | 432 | 2 (0)|00:00:01|
|*3 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 41 | 123 | 0 (0)| |
--------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
Join Optimizations
This section describes common join optimizations:
• Bloom Filters
• Partition-Wise Joins
Joins 9-35
Join Optimizations
Bloom Filters
A Bloom filter, named after its creator Burton Bloom, is a low-memory data structure
that tests membership in a set. A Bloom filter correctly indicates when an element is
not in a set, but can incorrectly indicate when an element is in a set. Thus, false
negatives are impossible but false positives are possible.
• Test whether data exists in the server result cache, thereby avoiding a disk read
• Filter members in Exadata cells, especially when joining a large fact table and small
dimension tables in a star schema
Bloom filters can occur in both parallel and serial processing.
This array represents a set. To represent an input value i in this array, three separate
hash functions (an arbitrary number used for this example) are applied to i, each
generating a hash value between 1 and 8:
f1(i) = h1
f2(i) = h2
f3(i) = h3
For example, to store the value 17 in this array, the hash functions set i to 17, and then
return the following hash values:
f1(17) = 5
f2(17) = 3
f3(17) = 5
In the preceding example, two of the hash functions happened to return the same
value of 5, known as a hash collision. Because the distinct hash values are 5 and 3, the
5th and 3rd elements in the array are set to 1:
e1 e2 e3 e4 e5 e6 e7 e8
0 0 1 0 1 0 0 0
Testing the membership of 17 in the set reverses the process. To test whether the set
excludes the value 17, element 3 or element 5 must contain a 0. If a 0 is present in
either element, then the set cannot contain 17. No false negatives are possible.
To test whether the set includes 17, both element 3 and element 5 must contain 1
values. However, if the test indicates a 1 for both elements, then it is still possible for
the set not to include 17. False positives are possible. For example, the following array
might represent the value 22, which also has a 1 for both element 3 and element 5:
e1 e2 e3 e4 e5 e6 e7 e8
1 0 1 0 1 0 0 0
See Also:
Oracle Database SQL Language Reference to learn more about the bloom filter
hints
• V$SQL_JOIN_FILTER
This view shows the number of rows filtered out (FILTERED column) and tested
(PROBED column) by an active Bloom filter.
• V$PQ_TQSTAT
This view displays the number of rows processed through each parallel execution
server at each stage of the execution tree. You can use it to monitor how much
Bloom filters have reduced data transfer among parallel processes.
In an execution plan, a Bloom filter is indicated by keywords JOIN FILTER in the
Operation column, and the prefix :BF in the Name column, as in the 9th step of the
following plan snippet:
----------------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------
...
| 9 | JOIN FILTER CREATE | :BF0000 | Q1,03 | PCWP | |
In the Predicate Information section of the plan, filters that contain functions
beginning with the string SYS_OP_BLOOM_FILTER indicate use of a Bloom filter.
Joins 9-37
Join Optimizations
----------------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10003 | Q1,03 | P->S | QC (RAND) |
|* 3 | HASH JOIN BUFFERED | | Q1,03 | PCWP | |
| 4 | PX RECEIVE | | Q1,03 | PCWP | |
| 5 | PX SEND BROADCAST | :TQ10001 | Q1,01 | S->P | BROADCAST |
| 6 | PX SELECTOR | | Q1,01 | SCWC | |
| 7 | TABLE ACCESS FULL | PRODUCTS | Q1,01 | SCWP | |
|* 8 | HASH JOIN | | Q1,03 | PCWP | |
| 9 | JOIN FILTER CREATE | :BF0000 | Q1,03 | PCWP | |
| 10 | BUFFER SORT | | Q1,03 | PCWC | |
| 11 | PX RECEIVE | | Q1,03 | PCWP | |
| 12 | PX SEND HYBRID HASH| :TQ10000 | | S->P | HYBRID HASH|
|* 13 | TABLE ACCESS FULL | TIMES | | | |
| 14 | PX RECEIVE | | Q1,03 | PCWP | |
| 15 | PX SEND HYBRID HASH | :TQ10002 | Q1,02 | P->P | HYBRID HASH|
| 16 | JOIN FILTER USE | :BF0000 | Q1,02 | PCWP | |
| 17 | PX BLOCK ITERATOR | | Q1,02 | PCWC | |
|* 18 | TABLE ACCESS FULL | SALES | Q1,02 | PCWP | |
----------------------------------------------------------------------------
3 - access("S"."PROD_ID"="P"."PROD_ID")
8 - access("S"."TIME_ID"="T"."TIME_ID")
13 - filter("T"."FISCAL_WEEK_NUMBER"=18)
18 - access(:Z>=:Z AND :Z<=:Z)
filter(SYS_OP_BLOOM_FILTER(:BF0000,"S"."TIME_ID"))
A single server process scans the times table (Step 13), and then uses a hybrid hash
distribution method to send the rows to the parallel execution servers (Step 12). The
processes in set Q1,03 create a bloom filter (Step 9). The processes in set Q1,02 scan
sales in parallel (Step 18), and then use the Bloom filter to discard rows from sales
(Step 16) before sending them on to set Q1,03 using hybrid hash distribution (Step
15). The processes in set Q1,03 hash join the times rows to the filtered sales rows
(Step 8). The processes in set Q1,01 scan products (Step 7), and then send the rows
to Q1,03 (Step 5). Finally, the processes in Q1,03 join the products rows to the rows
generated by the previous hash join (Step 3).
The basic process looks as follows:
Q1, 03
Create
Bloom filter
:BF0000
Q1, 01 Q1, 02
Partition-Wise Joins
A partition-wise join is a join optimization that divides a large join of two tables, one
of which must be partitioned on the join key, into several smaller joins. Partition-wise
joins are either of the following:
See Also:
Joins 9-39
Join Optimizations
t1 t2
PE Coordinator
t1 t2
PE Server
PE Server
PE Server
PE Server
A full partition-wise join can also join partitions to subpartitions, which is useful when
the tables use different partitioning methods. For example, customers is partitioned
by hash, but sales is partitioned by range. If you subpartition sales by hash, then
the database can perform a full partition-wise join between the hash partitions of the
customers and the hash subpartitions of sales.
In the execution plan, the presence of a partition operation before the join signals the
presence of a full partition-wise join, as in the following snippet:
| 8 | PX PARTITION HASH ALL|
|* 9 | HASH JOIN |
See Also:
Oracle Database VLDB and Partitioning Guide explains full partition-wise joins
in detail, and includes several examples
PE Coordinator
t1 t2
PE Server
PE Server t1 t2
PE Server
PE Server
PE Server
PE Server
PE Server
PE Server
Dynamically created
partitions
In the execution plan, the operation PX SEND PARTITION (KEY) signals a partial
partition-wise join, as in the following snippet:
Joins 9-41
Join Optimizations
See Also:
Oracle Database VLDB and Partitioning Guide explains full partition-wise joins
in detail, and includes several examples
• Histograms
See Also:
• Histograms
• Table statistics
– Number of rows
– Number of blocks
• Column statistics
– Extended statistics
• Index statistics
– Number of levels
• System statistics
Note:
The optimizer statistics are different from the performance statistics visible
through V$ views.
Database
Optimizer
Data Dictionary
Optimizer Statistics
PERSON
Table GB Execution
Plan
ID Name HJ
100 Kumar HJ
PERSON_ID_IX
• Table Statistics
• Column Statistics
• Index Statistics
• System Statistics
Table Statistics
In Oracle Database, table statistics include information about rows and blocks. The
optimizer uses these statistics to determine the cost of table scans and table joins.
DBMS_STATS can gather statistics for both permanent and temporary tables.
See Also:
Column Statistics
Column statistics track information about column values and data distribution. The
optimizer uses these statistics to generate accurate cardinality estimates and make
better decisions about index usage, join orders, join methods, and so on.
For example, index statistics in DBA_TAB_COL_STATISTICS track the following:
• Number of nulls
See Also:
Index Statistics
The index statistics include information about the number of index levels, the number
of index blocks, and the relationship between the index and the data blocks. The
optimizer uses these statistics to determine the cost of index scans.
• Levels
The BLEVEL column shows the number of blocks required to go from the root
block to a leaf block. A B-tree index has two types of blocks: branch blocks for
searching and leaf blocks that store values. See Oracle Database Concepts for a
conceptual overview of B-tree indexes.
• Distinct keys
This columns tracks the number of distinct indexed values. If a unique constraint is
defined, and if no NOT NULL constraint is defined, then this value equals the
number of non-null values.
See Also:
1. Start SQL*Plus and connect to a database as sh, and then query the number of
rows and blocks in the sh.customers table (sample output included):
SELECT table_name, num_rows, blocks
FROM user_tables
WHERE table_name='CUSTOMERS';
The table customers3 has the same data as the original customers table, but
the index on customers3 has a much lower clustering factor because the data in
the table is ordered by the cust_last_name. The clustering factor is now about
10 times the number of blocks instead of 70 times.
CUST_FIRST_NAME CUST_LAST_NAME
-------------------- ----------------------------------------
Vida Puleo
Harriett Quinlan
Madeleine Quinn
Caresse Puleo
For example, execute the following query (partial sample output included):
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows |Bytes|Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 405 (100)| |
|* 1| TABLE ACCESS STORAGE FULL| CUSTOMERS | 2335|35025| 405 (1)|00:00:01|
-------------------------------------------------------------------------------
The preceding plan shows that the optimizer did not use the index on the original
customers tables.
CUST_FIRST_NAME CUST_LAST_NAME
-------------------- ----------------------------------------
Vida Puleo
Harriett Quinlan
Madeleine Quinn
Caresse Puleo
For example, execute the following query (partial sample output included):
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
---------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)| Time|
---------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |69(100)| |
| 1| TABLE ACCESS BY INDEX ROWID|CUSTOMERS3 |2335|35025|69(0) |00:00:01|
|*2| INDEX RANGE SCAN |CUSTOMERS3_LAST_NAME_IDX|2335| |7(0) |00:00:01|
---------------------------------------------------------------------------------------
The result set is the same, but the optimizer chooses the index. The plan cost is
much less than the cost of the plan used on the original customers table.
13. Query customers with a hint that forces the optimizer to use the index.
For example, execute the following query (partial sample output included):
SELECT /*+ index (Customers CUSTOMERS_LAST_NAME_IDX) */ cust_first_name,
cust_last_name
FROM customers
WHERE cust_last_name BETWEEN 'Puleo' and 'Quinn';
CUST_FIRST_NAME CUST_LAST_NAME
-------------------- ----------------------------------------
Vida Puleo
Caresse Puleo
Harriett Quinlan
Madeleine Quinn
For example, execute the following query (partial sample output included):
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
-----------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost(%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 422(100) | |
| 1| TABLE ACCESS BY INDEX ROWID|CUSTOMERS |335 |35025| 422(0) |00:00:01|
|*2| INDEX RANGE SCAN |CUSTOMERS_LAST_NAME_IDX|2335| | 7(0) |00:00:01|
-----------------------------------------------------------------------------------------
The preceding plan shows that the cost of using the index on customers is
higher than the cost of a full table scan. Thus, using an index does not necessarily
improve performance. The index clustering factor is a measure of whether an
index scan is more effective than a full table scan.
In this example, the index clustering factor for col1_idx is low. The rows that have
the same indexed column values for col1 are in the same data blocks in the table.
Thus, the cost of using an index range scan to return all rows with value A is low
because only one block in the table must be read.
Example 10-5 Scattered Data
Assume that the same rows are scattered across the data blocks as follows:
Block 1 Block 2 Block 3
------- ------- -------
A B C A C B B A C
In this example, the index clustering factor for col1_idx is higher. The database must
read all three blocks in the table to retrieve all rows with the value A in col1.
See Also:
Oracle Database Reference for a description of the DBA_INDEXES view
• Dictionary views that track statistics show both the shared statistics and the
session-specific statistics in the current session.
The views are DBA_TAB_STATISTICS, DBA_IND_STATISTICS,
DBA_TAB_HISTOGRAMS, and DBA_TAB_COL_STATISTICS (each view has a
corresponding USER_ and ALL_ version). The SCOPE column shows whether
statistics are session-specific or shared.
• Other sessions do not share the cursor using the session-specific statistics.
Different sessions can share the cursor using shared statistics, as in releases earlier
than Oracle Database 12c. The same session can share the cursor using session-
specific statistics.
empty. Starting in Oracle Database 12c, the following procedures do not commit for
transaction-specific temporary tables, so that rows in these tables are not deleted:
• GATHER_TABLE_STATS
• DELETE_TABLE_STATS
• DELETE_COLUMN_STATS
• DELETE_INDEX_STATS
• SET_TABLE_STATS
• SET_COLUMN_STATS
• SET_INDEX_STATS
• GET_TABLE_STATS
• GET_COLUMN_STATS
• GET_INDEX_STATS
The preceding program units observe the GLOBAL_TEMP_TABLE_STATS preference.
For example, if the table preference is set to SESSION, then SET_TABLE_STATS sets
the session statistics, and GATHER_TABLE_STATS preserves all rows in a transaction-
specific temporary table. If the table preference is set to SHARED, then
SET_TABLE_STATS sets the shared statistics, and GATHER_TABLE_STATS deletes all
rows from a transaction-specific temporary table.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
System Statistics
The system statistics describe hardware characteristics such as I/O and CPU
performance and utilization. System statistics enable the query optimizer to more
accurately estimate I/O and CPU costs when choosing execution plans.
The database does not invalidate previously parsed SQL statements when updating
system statistics. The database parses all new SQL statements using new statistics.
See Also:
“Gathering System Statistics Manually”
See Also:
• DBMS_STATS Package
• Dynamic Statistics
See Also:
DBMS_STATS Package
The DBMS_STATS PL/SQL package collects and manages optimizer statistics. This
package enables you to control what and how statistics are collected, including the
degree of parallelism for statistics collection, sampling methods, granularity of
statistics collection in partitioned tables, and so on.
Note:
Do not use the COMPUTE and ESTIMATE clauses of the ANALYZE statement to
collect optimizer statistics. These clauses have been deprecated. Instead, use
DBMS_STATS.
Statistics gathered with the DBMS_STATS package are required for the creation of
accurate execution plans. For example, table statistics gathered by DBMS_STATS
include the number of rows, number of blocks, and average row length.
By default, Oracle Database uses automatic optimizer statistics collection. In this case,
the database automatically runs DBMS_STATS to collect optimizer statistics for all
schema objects for which statistics are missing or stale. The process eliminates many
manual tasks associated with managing the optimizer, and significantly reduces the
risks of generating suboptimal execution plans because of missing or stale statistics.
You can also update and manage optimizer statistics by manually executing
DBMS_STATS.
See Also:
Dynamic Statistics
By default, when optimizer statistics are missing, stale, or insufficient, the database
automatically gathers dynamic statistics during a parse. The database uses recursive
SQL to scan a small random sample of table blocks.
Note:
Dynamic statistics can supplement statistics such as table and index block counts, table
and join cardinalities (estimated number of rows), join column statistics, and GROUP
BY statistics. This information helps the optimizer improve plans by making better
estimates for predicate selectivity.
Dynamic statistics are beneficial in the following situations:
• The sampling time is a small fraction of total execution time for the query.
• The query is executed many times so that the sampling time is amortized.
See Also:
• INSERT INTO ... SELECT into an empty table using a direct path insert
Note:
By default, a parallel insert uses a direct path insert. You can force a direct
path insert by using the /*+APPEND */ hint.
See Also:
Oracle Database Data Warehousing Guide to learn more about bulk loads
• Improved performance
Gathering statistics during the load avoids an additional table scan to gather table
statistics.
• Improved manageability
See Also:
The preceding example only gathers missing or stale statistics. The database does not
gather table and basic column statistics collected during the bulk load.
Note:
You can set the table preference options to GATHER AUTO on the tables that
you plan to bulk load. In this way, you need not explicitly set the options
parameter when running GATHER_TABLE_STATS.
See Also:
“Gathering Schema and Table Statistics”
Note:
The DBA_TAB_COL_STATISTICS.NOTES column is set to STATS_ON_LOAD
by a bulk load into an empty table. However, subsequent bulk loads into the
non-empty table do not reset the NOTES column. One method for determining
whether the database gathered statistics is to execute
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO, and then query
USER_TAB_MODIFICATIONS.INSERTS. If the query returns a row indicating
the number of rows loaded, then the statistics were not gathered automatically
during the most recent bulk load.
• It is a nested table.
• It is an external table.
See Also:
“Gathering Schema and Table Statistics”
See Also:
• SQL compilation
During SQL compilation, the database can augment the statistics previously
gathered by DBMS_STATS. In this stage, the database runs additional queries to
obtain more accurate information on how many rows in the tables satisfy the
WHERE clause predicates in the SQL statement (see “When the Database Samples
Data”).
• SQL execution
During execution, the database can further augment previously gathered statistics.
In this stage, Oracle Database collects the number of rows produced by every row
source during the execution of a SQL statement. At the end of execution, the
optimizer determines whether the estimated number of rows is inaccurate enough
to warrant reparsing at the next statement execution. If the cursor is marked for
reparsing, then the optimizer uses actual row counts from the previous execution
instead of estimates.
• SQL profiles
A SQL profile is a collection of auxiliary statistics on a query. The profile stores
these supplemental statistics in the data dictionary. The optimizer uses SQL
profiles during optimization to determine the most optimal plan (see “About SQL
Profiles”).
The database stores optimizer statistics in the data dictionary and updates or replaces
them as needed. You can query statistics in data dictionary views.
See Also:
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID b74nw722wjvy3, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'
The actual number of rows (A-Rows) returned by each operation in the plan
varies greatly from the estimates (E-Rows). This statement is a candidate for
automatic reoptimization (see “Automatic Reoptimization”).
EXEC DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE;
Initially, the database stores SQL plan directives in memory, and then writes them
to disk every 15 minutes. Thus, the preceding example calls
DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE to force the database to write the
directives to the SYSAUX tablespace.
Monitor directives using the views DBA_SQL_PLAN_DIRECTIVES and
DBA_SQL_PLAN_DIR_OBJECTS. Three entries appear in the views, one for the
customers table itself, and one for each of the correlated columns. Because the
customers query has the IS_REOPTIMIZABLE value of Y, if you reexecute the
statement, then the database will hard parse it again, and then generate a plan
based on the previous execution statistics.
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID b74nw722wjvy3, child number 1
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'
Note
-----
- cardinality feedback used for this statement
The Note section indicates that the database used reoptimization for this
statement. The estimated number of rows (E-Rows) is now correct. The SQL plan
directive has not been used yet.
A new plan exists for the customers query, and also a new child cursor.
8. Confirm that a SQL plan directive exists and is usable for other statements.
For example, run the following query, which is similar but not identical to the
original customers query (the state is MA instead of CA):
SELECT /*+gather_plan_statistics*/ CUST_EMAIL
FROM CUSTOMERS
WHERE CUST_STATE_PROVINCE='MA'
AND COUNTRY_ID='US';
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 3tk6hj3nkcs2u, child number 0
-------------------------------------
Select /*+gather_plan_statistics*/ cust_email From customers Where
cust_state_province='MA' And country_id='US'
---------------------------------------------------------------------------
|Id | Operation | Name |Starts|E-Rows|A-Rows| A-Time |Buffers|
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 |00:00:00.01| 16 |
|*1 | TABLE ACCESS FULL| CUSTOMERS | 1 | 2 | 2 |00:00:00.01| 16 |
---------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
- 1 Sql Plan Directive used for this statement
The Note section of the plan shows that the optimizer used the SQL directive for
this statement, and also used dynamic statistics.
See Also:
How the Optimizer Uses Extensions and SQL Plan Directives: Example
This example is a continuation of “How the Optimizer Uses SQL Plan Directives:
Example”. The example shows how the database uses a SQL plan directive until the
optimizer verifies that an extension exists and the statistics are applicable. At this
point, the directive changes its status to SUPERSEDED. Subsequent compilations use
the statistics instead of the directive.
Assumptions
This example assumes you have already followed the steps in “How the Optimizer
Uses SQL Plan Directives: Example”.
To see how the optimizer uses an extension and SQL plan directive:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS('SH','CUSTOMERS');
END;
/
The preceding output indicates that a column group extension exists on the
cust_state_province and country_id columns.
7. Query the sh.customers table again, using a slightly different form of the
statement.
For example, run the following query:
SELECT /*+gather_plan_statistics*/ /* force reparse */ *
FROM customers
WHERE cust_state_province='CA'
AND country_id='US';
If the cursor is in the shared SQL area, then the database typically shares the
cursor. To force a reparse, this step changes the SQL text slightly by adding a
comment.
See Also:
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID b74nw722wjvy3, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 29 |00:00:00.01 | 16 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 1 | 29 | 29 |00:00:00.01 | 16 |
-----------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
- 1 Sql Plan Directive used for this statement
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID b74nw722wjvy3, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 29 |00:00:00.01 | 17 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 1 | 29 | 29 |00:00:00.01 | 17 |
-----------------------------------------------------------------------------------------
19 rows selected.
• The SQL statement is known to the database, which means that it was captured in
SQL Plan Management or Automatic Workload Repository, or is currently in the
shared SQL area.
Figure 10-2 illustrates the process of gathering dynamic statistics.
Optimizer
GB Execution
Plan
Statistics missing?
Statistics stale? HJ
No HJ
Statistics insufficient?
SQL directive exists?
Parallel execution?
Yes
Sales
As shown in Figure 10-2, the optimizer automatically gathers dynamic statistics in the
following cases:
• Missing statistics
When tables in a query have no statistics, the optimizer gathers basic statistics on
these tables before optimization. Statistics can be missing because the application
creates new objects without a follow-up call to DBMS_STATS to gather statistics, or
because statistics were locked on an object before statistics were gathered.
In this case, the statistics are not as high-quality or as complete as the statistics
gathered using the DBMS_STATS package. This trade-off is made to limit the
impact on the compile time of the statement.
• Stale statistics
Statistics gathered by DBMS_STATS can become out-of-date. Typically, statistics are
stale when 10% or more of the rows in the table have changed since the last time
statistics were gathered.
For an example of the problem posed by stale statistics, consider a sales table that
includes the sales date. After an application inserts new rows, the maximum
statistics on the sales date column becomes stale because new rows have a higher
sales date than the maximum value seen during the last statistics gathering. For
any query that fetches the most recently added sales data, the optimizer assumes
that table access will return very few or no rows, which leads to the selection of a
suboptimal access path to the sales table (for example, the index on the sales date
column), a suboptimal join method (typically a cartesian product), or an inefficient
join order. This is commonly known as the out-of-range condition: the value specified
in the predicate on the sales date column is outside the column statistics value
domain.
• Insufficient statistics
Note:
The database does not use dynamic statistics for queries that contain the AS
OF clause.
See Also:
See Also:
• Hybrid histograms
This section contains the following topics:
• Purpose of Histograms
• Frequency Histograms
• Hybrid Histograms
Purpose of Histograms
By default the optimizer assumes a uniform distribution of rows across the distinct
values in a column. For columns that contain data skew (a nonuniform distribution of
data within the column), a histogram enables the optimizer to generate accurate
cardinality estimates for filter and join predicates that involve these columns.
For example, a California-based book store ships 95% of the books to California, 4% to
Oregon, and 1% to Nevada. The book orders table has 300,000 rows. A table column
stores the state to which orders are shipped. A user queries the number of books
shipped to Oregon. Without a histogram, the optimizer assumes an even distribution
of 300000/3 (the NDV is 3), estimating cardinality at 100,000 rows. With this estimate,
the optimizer chooses a full table scan. With a histogram, the optimizer calculates that
4% of the books are shipped to Oregon, and chooses an index scan.
See Also:
“Introduction to Access Paths”
Histograms 11-1
When Oracle Database Creates Histograms
1. You run DBMS_STATS for a table with the METHOD_OPT parameter set to the
default SIZE AUTO.
3. The database notes the predicates in the preceding query and updates the data
dictionary table SYS.COL_USAGE$.
• As queries change over time, DBMS_STATS may change which statistics it gathers.
For example, even if the data in a table does not change, queries and DBMS_STATS
operations can cause the plans for queries that reference these tables to change.
• If you gather statistics for a table and do not query the table, then the database does
not create histograms for columns in this table. For the database to create the
histograms automatically, you must run one or more queries to populate the
column usage information in SYS.COL_USAGE$.
Example 11-1 Automatic Histogram Creation
Assume that sh.sh_ext is an external table that contains the same rows as the
sh.sales table. You create new table sales2 and perform a bulk load using sh_ext
as a source, which automatically creates statistics for sales2 (see “Online Statistics
Gathering for Bulk Loads”). You also create indexes as follows:
SQL> CREATE TABLE sales2 AS SELECT * FROM sh_ext;
SQL> CREATE INDEX sh_12c_idx1 ON sales2(prod_id);
SQL> CREATE INDEX sh_12c_idx2 ON sales2(cust_id,time_id);
You query the data dictionary to determine whether histograms exist for the sales2
columns. Because sales2 has not yet been queried, the database has not yet created
histograms:
SQL> SELECT COLUMN_NAME, NOTES, HISTOGRAM
2 FROM USER_TAB_COL_STATISTICS
3 WHERE TABLE_NAME = 'SALES2';
You query sales2 for the number of rows for product 42, and then gather table
statistics using the GATHER AUTO option:
SQL> SELECT COUNT(*) FROM sales2 WHERE prod_id = 42;
COUNT(*)
----------
12116
A query of the data dictionary now shows that the database created a histogram on
the prod_id column based on the information gather during the preceding query:
SQL> SELECT COLUMN_NAME, NOTES, HISTOGRAM
2 FROM USER_TAB_COL_STATISTICS
3 WHERE TABLE_NAME = 'SALES2';
• NDV
This represents the number of distinct values in a column. For example, if a column
only contains the values 100, 200, and 300, then the NDV for this column is 3.
• n
This variable represents the number of histogram buckets. The default is 254.
• p
This variable represents an internal percentage threshold that is equal to (1–(1/n)) *
100. For example, if n = 254, then p is 99.6.
An additional criterion is whether the estimate_percent parameter in the
DBMS_STATS statistics gathering procedure is set to AUTO_SAMPLE_SIZE (default).
The following diagram shows the decision tree for histogram creation.
Histograms 11-3
Cardinality Algorithms When Using Histograms
No No No
• Bucket Compression
• Popular values
A popular value occurs as an endpoint value of multiple buckets. The optimizer
determines whether a value is popular by first checking whether it is the endpoint
value for a bucket. If so, then for frequency histograms, the optimizer subtracts the
endpoint number of the previous bucket from the endpoint number of the current
bucket. Hybrid histograms already store this information for each endpoint
individually. If this value is greater than 1, then the value is popular.
The optimizer calculates its cardinality estimate for popular values using the
following formula:
cardinality of popular value =
(num of rows in table) *
(num of endpoints spanned by this value / total num of endpoints)
• Nonpopular values
Any value that is not popular is a nonpopular value. The optimizer calculates the
cardinality estimates for nonpopular values using the following formula:
cardinality of nonpopular value =
(num of rows in table) * density
The optimizer calculates density using an internal algorithm based on factors such
as the number of buckets and the NDV. Density is expressed as a decimal number
between 0 and 1. Values close to 1 indicate that the optimizer expects many rows
to be returned by a query referencing this column in its predicate list. Values close
to 0 indicate that the optimizer expects few rows to be returned.
See Also:
Bucket Compression
In some cases, to reduce the total number of buckets, the optimizer compresses
multiple buckets into a single bucket. For example, the following frequency histogram
indicates that the first bucket number is 1 and the last bucket number is 23:
ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1 52792
6 52793
8 52794
9 52795
10 52796
12 52797
14 52798
23 52799
Several buckets are "missing." Originally, buckets 2 through 6 each contained a single
instance of value 52793. The optimizer compressed all of these buckets into the
bucket with the highest endpoint number (bucket 6), which now contains 5 instances
of value 52793. This value is popular because the difference between the endpoint
number of the current bucket (6) and the previous bucket (1) is 5. Thus, before
compression the value 52793 was the endpoint for 5 buckets.
The following annotations show which buckets are compressed, and which values are
popular:
ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1 52792 -> nonpopular
6 52793 -> buckets 2-6 compressed into 6; popular
8 52794 -> buckets 7-8 compressed into 8; popular
9 52795 -> nonpopular
Histograms 11-5
Frequency Histograms
Frequency Histograms
In a frequency histogram, each distinct column value corresponds to a single bucket
of the histogram. Because each value has its own dedicated bucket, some buckets may
have many values, whereas others have few.
An analogy to a frequency histogram is sorting coins so that each individual coin
initially gets its own bucket. For example, the first penny is in bucket 1, the second
penny is in bucket 2, the first nickel is in bucket 3, and so on. You then consolidate all
the pennies into a single penny bucket, all the nickels into a single nickel bucket, and
so on with the remainder of the coins.
This section contains the following topics:
• NDV is less than or equal to n, where n is the number of histogram buckets (default
254).
For example, the sh.countries.country_subregion_id column has 8
distinct values, ranging sequentially from 52792 to 52799. If n is the default of
254, then the optimizer creates a frequency histogram because 8 <= 254.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about
AUTO_SAMPLE_SIZE , and Oracle Database Administrator’s Guide *** to learn
about application common objects BPT this is a test ***
Assumptions
This scenario assumes that you want to generate a frequency histogram on the
sh.countries.country_subregion_id column. This table has 23 rows.
The following query shows that the country_subregion_id column contains 8
distinct values (sample output included) that are unevenly distributed:
SELECT country_subregion_id, count(*)
FROM sh.countries
GROUP BY country_subregion_id
ORDER BY 1;
COUNTRY_SUBREGION_ID COUNT(*)
-------------------- ----------
52792 1
52793 5
52794 2
52795 1
52796 1
52797 2
52798 2
52799 9
Histograms 11-7
Frequency Histograms
AND COLUMN_NAME='COUNTRY_SUBREGION_ID';
ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1 52792
6 52793
8 52794
9 52795
10 52796
12 52797
14 52798
23 52799
Figure 11-2 is a graphical illustration of the 8 buckets in the histogram. Each value
is represented as a coin that is dropped into a bucket.
52793 52793
52799
52799 52799
As shown in Figure 11-2, each distinct value has its own bucket. Because this is a
frequency histogram, the endpoint number is the cumulative frequency of
endpoints. For 52793, the endpoint number 6 indicates that the value appears 5
times (6 - 1). For 52794, the endpoint number 8 indicates that the value appears 2
times (8 - 6).
Every bucket whose endpoint is at least 2 greater than the previous endpoint
contains a popular value. Thus, buckets 6, 8, 12, 14, and 23 contain popular
values. The optimizer calculates their cardinality based on endpoint numbers. For
Histograms 11-9
Top Frequency Histograms
example, the optimizer calculates the cardinality (C) of value 52799 using the
following formula, where the number of rows in the table is 23:
C = 23 * ( 9 / 23 )
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
• NDV is greater than n, where n is the number of histogram buckets (default 254).
• The percentage of rows occupied by the top n frequent values is equal to or greater
than threshold p, where p is (1-(1/n))*100.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about
AUTO_SAMPLE_SIZE
Assumptions
This scenario assumes that you want to generate a top frequency histogram on the
sh.countries.country_subregion_id column. This table has 23 rows.
The following query shows that the country_subregion_id column contains 8
distinct values (sample output included) that are unevenly distributed:
SELECT country_subregion_id, count(*)
FROM sh.countries
GROUP BY country_subregion_id
ORDER BY 1;
COUNTRY_SUBREGION_ID COUNT(*)
-------------------- ----------
52792 1
52793 5
52794 2
52795 1
52796 1
52797 2
52798 2
52799 9
Histograms 11-11
Top Frequency Histograms
3. Query the endpoint number and endpoint value for the column.
For example, use the following query (sample output included):
SELECT ENDPOINT_NUMBER, ENDPOINT_VALUE
FROM USER_HISTOGRAMS
WHERE TABLE_NAME='COUNTRIES'
AND COLUMN_NAME='COUNTRY_SUBREGION_ID';
ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1 52792
6 52793
8 52794
9 52796
11 52797
13 52798
22 52799
52793 52793
52799
52799 52799
As shown in Figure 11-3, each distinct value has its own bucket except for 52795,
which is excluded from the histogram because it is nonpopular and statistically
insignificant. As in a standard frequency histogram, the endpoint number
represents the cumulative frequency of values.
Histograms 11-13
Height-Balanced Histograms (Legacy)
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
• NDV is greater than n, where n is the number of histogram buckets (default 254).
Note:
If you upgrade Oracle Database 11g to Oracle Database 12c, then any height-
based histograms created before the upgrade remain in use. If Oracle Database
12c creates new histograms, and if the sampling percentage is
AUTO_SAMPLE_SIZE, then the histograms are either top frequency or hybrid,
but not height-balanced.
Assumptions
This scenario assumes that you want to generate a height-balanced histogram on the
sh.countries.country_subregion_id column. This table has 23 rows.
COUNTRY_SUBREGION_ID COUNT(*)
-------------------- ----------
52792 1
52793 5
52794 2
52795 1
52796 1
52797 2
52798 2
52799 9
Note:
Histograms 11-15
Height-Balanced Histograms (Legacy)
NUM_OF_ROWS COUNTRY_SUBREGION_ID
----------- --------------------
1 52792
5 52793
2 52794
1 52795
1 52796
2 52797
2 52798
9 52799
ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
0 52792
2 52793
3 52795
4 52798
7 52799
52799
52799 52799
The bucket number is identical to the endpoint number. The optimizer records the
value of the last row in each bucket as the endpoint value, and then checks to
ensure that the minimum value is the endpoint value of the first bucket, and the
maximum value is the endpoint value of the last bucket. In this example, the
optimizer adds bucket 0 so that the minimum value 52792 is the endpoint of a
bucket.
The optimizer must evenly distribute 23 rows into the 7 specified histogram
buckets, so each bucket contains approximately 3 rows. However, the optimizer
compresses buckets with the same endpoint. So, instead of bucket 1 containing 2
instances of value 52793, and bucket 2 containing 3 instances of value 52793, the
optimizer puts all 5 instances of value 52793 into bucket 2. Similarly, instead of
having buckets 5, 6, and 7 contain 3 values each, with the endpoint of each bucket
as 52799, the optimizer puts all 9 instances of value 52799 into bucket 7.
In this example, buckets 3 and 4 contain nonpopular values because the
difference between the current endpoint number and previous endpoint number
is 1. The optimizer calculates cardinality for these values based on density. The
remaining buckets contain popular values. The optimizer calculates cardinality for
these values based on endpoint numbers.
Histograms 11-17
Hybrid Histograms
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
Hybrid Histograms
A hybrid histogram combines characteristics of both height-based histograms and
frequency histograms. This "best of both worlds" approach enables the optimizer to
obtain better selectivity estimates in some situations.
The height-based histogram sometimes produces inaccurate estimates for values that
are almost popular. For example, a value that occurs as an endpoint value of only one
bucket but almost occupies two buckets is not considered popular.
To solve this problem, a hybrid histogram distributes values so that no value occupies
more than one bucket, and then stores the endpoint repeat count value, which is the
number of times the endpoint value is repeated, for each endpoint (bucket) in the
histogram. By using the repeat count, the optimizer can obtain accurate estimates for
almost popular values.
This section contains the following topics:
1 1 1 5 5 5 10 10 25 25 25 25 50 100 100
You gather statistics for this table, setting the method_opt argument of
DBMS_STATS.GATHER_TABLE_STATS to FOR ALL COLUMNS SIZE 3. In this case,
the optimizer initially groups the values in coins into three buckets, as follows:
1 1 1 5 10 10 25 25 50
5 5 25 25 100 100
If a bucket border splits a value so that some occurrences of the value are in one
bucket and some in another, then the optimizer shifts the bucket border (and all other
following bucket borders) forward to include all occurrences of the value. For
example, the optimizer shifts value 5 so that it is now wholly in the first bucket, and
the value 25 is now wholly in the second bucket:
1 1 1 10 10 50
5 5 25 25 100 100
5 25 25
The endpoint repeat count measures the number of times that the corresponding
bucket endpoint, which is the value at the right bucket border, repeats itself. For
example, in the first bucket, the value 5 is repeated 3 times, so the endpoint repeat
count is 3:
Histograms 11-19
Hybrid Histograms
1 1 1 10 10 50
5 5 25 25 100 100
5 25 25
• NDV is greater than n, where n is the number of histogram buckets (default is 254).
See Also:
“Height-Balanced Histograms (Legacy)”
Assumptions
This scenario assumes that you want to generate a hybrid histogram on the
sh.products.prod_subcategory_id column. This table has 72 rows. The
prod_subcategory_id column contains 22 distinct values.
NUM_OF_ROWS PROD_SUBCATEGORY_ID
----------- -------------------
8 2014
7 2055
6 2032
6 2054
5 2056
5 2031
5 2042
5 2051
4 2036
3 2043
2 2033
2 2034
2 2013
2 2012
2 2053
2 2035
1 2022
1 2041
1 2044
1 2011
1 2021
1 2052
22 rows selected.
The column contains 22 distinct values. Because the number of buckets (10) is less
than 22, the optimizer cannot create a frequency histogram. The optimizer
considers both hybrid and top frequency histograms. To qualify for a top
frequency histogram, the percentage of rows occupied by the top 10 most frequent
values must be equal to or greater than threshold p, where p is (1-(1/10))*100, or
Histograms 11-21
Hybrid Histograms
90%. However, in this case the top 10 most frequent values occupy 54 rows out of
72, which is only 75% of the total. Therefore, the optimizer chooses a hybrid
histogram because the criteria for a top frequency histogram do not apply.
4. Query the endpoint number, endpoint value, and endpoint repeat count for the
country_subregion_id column.
For example, use the following query (sample output included):
SELECT ENDPOINT_NUMBER, ENDPOINT_VALUE, ENDPOINT_REPEAT_COUNT
FROM USER_HISTOGRAMS
WHERE TABLE_NAME='PRODUCTS'
AND COLUMN_NAME='PROD_SUBCATEGORY_ID'
ORDER BY 1;
10 rows selected.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
Histograms 11-23
Hybrid Histograms
See Also:
See Also:
“Gathering Optimizer Statistics Manually”
3. In the list of database targets, select the target for the Oracle Database instance
that you want to administer.
See Also:
See Also:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn how to use
DBMS_STATS and DBMS_AUTO_TASK_ADMIN
Note:
Data visibility and privilege requirements may differ when using automatic
optimizer statistics collection with pluggable databases. See Oracle Database
Administrator’s Guide for a table that summarizes how manageability features
work in a container database (CDB).
To collect the optimizer statistics, the database calls an internal procedure that
operates similarly to the GATHER_DATABASE_STATS procedure with the GATHER
AUTO option. Automatic statistics collection honors all preferences set in the database.
The principal difference between manual and automatic collection is that the latter
prioritizes database objects that need statistics. Before the maintenance window closes,
automatic collection assesses all objects and prioritizes objects that have no statistics or
very old statistics.
Note:
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
3. Click Configure.
The Automated Maintenance Tasks Configuration page appears.
a. In the Task Settings section for Optimizer Statistics Gathering, select either
Enabled or Disabled to enable or disable an automated task.
Note:
b. To disable statistics gathering for specific days in the week, check the
appropriate box next to the window name.
d. To change the times for a window, click the name of the window (for
example, Monday Window), and then in the Schedule section, click Edit.
The Edit Window page appears.
In this page, you can change the parameters such as duration and start time
for window execution.
e. Click Apply.
See Also:
Note:
Because monitoring and many automatic features are disabled, Oracle
strongly recommends that you do not set STATISTICS_LEVEL to BASIC.
1. Connect SQL*Plus to the database with administrator privileges, and then do one
of the following:
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_AUTO_TASK_ADMIN package
See Also:
1. Table preference (set for a specific table, all tables in a schema, or all tables in the
database)
2. Global preference
3. Default preference
The following table summarizes the relevant DBMS_STATS procedures.
Procedure Scope
SET_TABLE_PREFS Specified table only.
SET_GLOBAL_PREFS Any table in the database that does not have an existing table
preference.
All parameters default to the global setting unless a table
preference is set or the parameter is explicitly set in the
DBMS_STATS.GATHER_*_STATS command. Changes made
by this procedure affect any new objects created after it runs.
New objects use the SET_GLOBAL_PREF values for all
parameters.
With SET_GLOBAL_PREFS, you can set a default value for the
parameter AUTOSTAT_TARGET. This additional parameter
controls which objects the automatic statistic gathering job
running in the nightly maintenance window looks after.
Possible values for this parameter are ALL, ORACLE, and AUTO
(default).
You can only set the CONCURRENT preference at the global
level). You cannot set the preference INCREMENTAL_LEVEL
using SET_GLOBAL_PREFS.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS procedures for setting optimizer statistics
Action Description
STAT_PREFS
----------
TRUE
STAT_PREFS
----------
FALSE
STAT_PREFS
----------
TRUE
STAT_PREFS
----------
FALSE
See Also:
3. To modify table preferences for a table that has preferences set at the table level,
do the following (otherwise, skip to the next step):
a. Enter values in Schema and Table. Leave Table blank to see all tables in the
schema.
The page refreshes with the table names.
4. To set preferences for a table that does not have preferences set at the table level,
do the following (otherwise, skip to the next step):
See Also:
Prerequisites
This task has the following prerequisites:
• To set the global or database preferences, you must have SYSDBA privileges, or
both ANALYZE ANY DICTIONARY and ANALYZE ANY system privileges.
• To set schema preferences, you must connect as owner, or have SYSDBA privileges,
or have the ANALYZE ANY system privilege.
• To set table preferences, you must connect as owner of the table or have the
ANALYZE ANY system privilege.
3. Execute the appropriate procedure from Table 12-1, specifying the following
parameters:
See Also:
Oracle Database PL/SQL Packages and Types Reference for descriptions of the
parameter names and values for program units
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS packages
Procedure Purpose
GATHER_INDEX_STATS Collects index statistics
When the OPTIONS parameter is set to GATHER STALE or GATHER AUTO, the
GATHER_SCHEMA_STATS and GATHER_DATABASE_STATS procedures gather
statistics for any table that has stale statistics and any table that is missing statistics. If
a monitored table has been modified more than 10%, then the database considers these
statistics stale and gathers them again.
Note:
See Also:
Oracle Database PL/SQL Packages and Types Reference for complete syntax and
semantics for the DBMS_STATS package
• You perform certain types of bulk load and cannot wait for the maintenance
window to collect statistics because queries must be executed immediately. See
“Online Statistics Gathering for Bulk Loads”.
• Automatic statistics collection does not gather system statistics. See “Gathering
System Statistics Manually”.
• Volatile tables are being deleted or truncated, and then rebuilt during the day. See
“Gathering Statistics for Volatile Tables Using Dynamic Statistics”.
This section offers guidelines for typical situations in which you may choose to gather
statistically manually:
• Incremental statistics
• Concurrent statistics
The database can gather most statistics serially or in parallel. However, the database
does not gather some index statistics in parallel, including cluster indexes, domain
indexes, and bitmap join indexes. The database can use sampling when gathering
parallel statistics.
Note:
Do not confuse gathering statistics in parallel with gathering statistics
concurrently. See “About Concurrent Statistics Gathering”.
See Also:
• YES
The statistics are stale.
• NO
The statistics are not stale.
• null
The statistics are not collected.
Executing GATHER_SCHEMA_STATS or GATHER_DATABASE_STATS with the GATHER
AUTO option collects statistics only for objects with no statistics or stale statistics.
Assumptions
This tutorial assumes the following:
• You have the ANALYZE_ANY system privilege so you can run the
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO procedure.
PARTITION_NAME STA
--------------- ---
SALES_1995 NO
SALES_1996 NO
SALES_H1_1997 NO
SALES_H2_1997 NO
SALES_Q1_1998 NO
SALES_Q1_1999 NO
.
.
.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO procedure
1. Start SQL*Plus, and connect to the database with the appropriate privileges for
the procedure that you intend to run.
• Owner - ownname
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
GATHER_TABLE_STATS procedure
Prerequisites
You must have the SYSDBA or ANALYZE ANY DICTIONARY system privilege to
execute this procedure.
1. Start SQL*Plus, and connect to the database with the appropriate privileges for
the procedure that you intend to run.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
GATHER_TABLE_STATS procedure
Note:
Assumptions
This tutorial assumes the following:
• You want to delete and then lock the statistics on the orders table to prevent the
database from gathering statistics on the table. In this way, the database can
dynamically gather necessary statistics as part of query optimization.
1. Connect to the database as user oe, and then delete the statistics for the oe table.
For example, execute the following procedure:
BEGIN
DBMS_STATS.DELETE_TABLE_STATS('OE','ORDERS');
END;
/
---------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
---------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 2 (100)| |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| ORDERS | 105 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------
Note
-----
- dynamic statistics used for this statement (level=2)
The Note in the preceding execution plan shows that the database used dynamic
statistics for the SELECT statement.
See Also:
• Configuring the System for Parallel Execution and Concurrent Statistics Gathering
Note:
• Oracle Scheduler
The database runs as many concurrent jobs as possible. The Job Scheduler decides
how many jobs to execute concurrently and how many to queue. As running jobs
complete, the scheduler dequeues and runs more jobs until the database has gathered
statistics on all tables, partitions, and subpartitions. The maximum number of jobs is
bounded by the JOB_QUEUE_PROCESSES initialization parameter and available
system resources.
In most cases, the DBMS_STATS procedures create a separate job for each table
partition or subpartition. However, if the partition or subpartition is very small or
empty, the database may automatically batch the object with other small objects into a
single job to reduce the overhead of job maintenance.
The following figure illustrates the creation of jobs at different levels, where Table 3 is
a partitioned table, and the other tables are nonpartitioned. Job 3 acts as a coordinator
job for Table 3, and creates a job for each partition in that table, and a separate job for
the global statistics of Table 3. This example assumes that incremental statistics
gathering is disabled; if enabled, then the database derives global statistics from
partition-level statistics after jobs for partitions complete.
Level 1
Level 2
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
Note:
The ORA$AUTOTASK consumer group is shared with the maintenance tasks
that automatically run during the maintenance windows. Thus, when
concurrency is activated for automatic statistics gathering, the database
automatically manages resources, with no extra steps required.
See Also:
• MANUAL
Concurrency is enabled only for manual statistics gathering.
• AUTOMATIC
Concurrency is enabled only for automatic statistics gathering.
• ALL
Concurrency is enabled for both manual and automatic statistics gathering.
• OFF
Concurrency is disabled for both manual and automatic statistics gathering. This is
the default value.
This tutorial in this section explains how to enable concurrent statistics gathering.
Prerequisites
This tutorial has the following prerequisites:
• In addition to the standard privileges for gathering statistics, you must have the
following privileges:
– CREATE JOB
– MANAGE SCHEDULER
• The SYSAUX tablespace must be online because the scheduler stores its internal
tables and views in this tablespace.
Assumptions
This tutorial assumes that you want to do the following:
1. Connect SQL*Plus to the database with the appropriate privileges, and then
enable the Resource Manager.
The following example uses the default plan for the Resource Manager:
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'DEFAULT_PLAN';
DBMS_STATS.GET_PREFS('CONCURRENT')
----------------------------------
ALL
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn how to use the
DBMS_STATS.SET_GLOBAL_PREFS procedure
Configuring the System for Parallel Execution and Concurrent Statistics Gathering
When CONCURRENT statistics gathering is enabled, you can execute each statistics
gathering job in parallel. This combination is useful when you are analyzing large
3. Configure the database to use a resource plan that has parallel queuing enabled.
Perform the following steps:
See Also:
• DBA_OPTSTAT_OPERATION_TASKS
This view contains the history of tasks that are performed or currently in progress
as part of statistics gathering operations (recorded in
• DBA_OPTSTAT_OPERATIONS
This view contains a history of statistics operations performed or currently in
progress at the table, schema, and database level using the DBMS_STATS package.
The TARGET column in the preceding views shows the target object for that statistics
gathering job in the following form:
OWNER.TABLE_NAME.PARTITION_OR_SUBPARTITION_NAME
All statistics gathering job names start with the string ST$.
• To list statistics gathering currently running tasks from all user sessions, use the
following SQL statement (sample output included):
SELECT OPID, TARGET, JOB_NAnME,
(SYSTIMESTAMP - START_TIME) AS elapsed_time
FROM DBA_OPTSTAT_OPERATION_TASKS
WHERE STATUS = 'IN PROGRESS';
• To list only completed tasks and jobs from a particular operation, first identify the
operation ID from the DBA_OPTSTAT_OPERATIONS view based on the statistics
gathering operation name, target, and start time. After you identify the operation
ID, you can query the DBA_OPTSTAT_OPERATION_TASKS view to find the
corresponding tasks in that operation
For example, to list operations with the ID 981, use the following commands in
SQL*Plus (sample output included):
VARIABLE id NUMBER
EXEC :id := 985
See Also:
2. The database scans the changed partitions to gather their partition-level statistics.
The full scan of the table for global statistics collection can be very expensive,
depending on the size of the table. As the table adds partitions, the longer the
execution time for GATHER_TABLE_STATS because of the full table scan required for
the global statistics. The database must perform the scan of the entire table even if only
a small subset of partitions change. In contrast, incremental statistics enable the
database to avoid these full table scans.
Calculating the NDV in the table by adding the NDV of the individual partitions
produces an NDV of 9, which is incorrect. To solve this problem, the database
maintains a structure called a synopsis for each column at the partition level. A
synopsis can be viewed as a sample of distinct values. The database can accurately
derive the NDV for each column by merging partition-level synopses. In this example,
the database can correctly calculate the NDV as 6.
Example 12-3 Deriving Global Statistics
The following graphic shows how the database gathers statistics for the initial six
partitions of the sales table, and then creates synopses for each partition (S1, S2, and
so on). The database creates global statistics by aggregating the partition-level
statistics and synopses.
May 18 2012 S1
2 The database generates
1
global statistics by
May 19 2012 S2 aggregating partition-level
statistics and synopses
May 20 2012 S3
Global
Statistics
May 21 2012 S4
May 22 2012 S5
May 23 2012 S6
Sysaux
Tablespace
The following graphic shows a new partition, containing data for May 24, being added
to the sales table. The database gathers statistics for the newly added partition,
retrieves synopses for the other partitions, and then aggregates the synopses to create
global statistics.
Sales Table
May 18 2012 S1
1 The database generates
6
global statistics by
May 19 2012 S2 aggregating partition-level
synopses.
May 20 2012 S3
Global
Statistics
May 21 2012 S4
May 24 2012 S7
Sysaux
Tablespace
• The SYSAUX tablespace consumes additional space to maintain global statistics for
partitioned tables.
• If a table uses composite partitioning, then the database only gathers statistics for
modified subpartitions. The database does not gather statistics at the subpartition
level for unmodified subpartitions. In this way, the database reduces work by
skipping unmodified partitions.
• If a table uses incremental statistics, and if this table has a locally partitioned index,
then the database gathers index statistics at the global level and for modified (not
unmodified) index partitions. The database does not generate global index statistics
from the partition-level index statistics. Rather, the database gathers global index
statistics by performing a full index scan.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_STATS
• TABLE
DBMS_STATS gathers table-level synopses on this table. You can only set
INCREMENTAL_LEVEL to TABLE at the table level, not at the schema, database, or
global level.
• PARTITION (default)
DBMS_STATS only gathers synopsis at the partition level of partitioned tables.
When performing a partition exchange, to have synopses after the exchange for the
partition being exchanged, set INCREMENTAL to true and INCREMENTAL_LEVEL to
TABLE on the table to be exchanged with the partition.
Assumptions
This tutorial assumes the following:
• You create a staging table t_sales_01_2010, and then populate the table.
• You want the database to maintain incremental statistics as part of the partition
exchange operation without having to explicitly gather statistics on the partition
after the exchange.
, 't_sales_01_2010'
, 'INCREMENTAL'
, 'true'
);
DBMS_STATS.SET_TABLE_PREFS (
'sh'
, 't_sales_01_2010'
, 'INCREMENTAL_LEVEL'
, 'table'
);
END;
4. If you have never gathered statistics on sh.sales before with INCREMENTAL set
to true, then gather statistics on the partition to be exchanged.
For example, run the following PL/SQL code:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS (
'sh'
, 'sales'
, 'p_sales_01_2010'
, granularity=>'partition'
);
END;
/
After the exchange, the partitioned table has both statistics and a synopsis for
partition p_sales_01_2010.
In releases before Oracle Database 12c, the preceding statement swapped the
segment data and statistics of p_sales_01_2010 with t_sales_01_2010. The
database did not maintain synopses for nonpartitioned tables such as
t_sales_01_2010. To gather global statistics on the partitioned table, you
needed to rescan the p_sales_01_2010 partition to obtain its synopses.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_STATS.SET_TABLE_PREFS
Maintaining Incremental Statistics for Tables with Stale or Locked Partition Statistics
Starting in Oracle Database 12c, incremental statistics can automatically calculate
global statistics for a partitioned table even if the partition or subpartition statistics are
stale and locked.
When incremental statistics are enabled in releases before Oracle Database 12c, if any
DML occurs on a partition, then the optimizer considers statistics on this partition to
be stale. Thus, DBMS_STATS must gather the statistics again to accurately aggregate
the global statistics. Furthermore, if DML occurs on a partition whose statistics are
locked, then DBMS_STATS cannot regather the statistics on the partition, so a full table
scan is the only means of gathering global statistics. The necessity to regather statistics
creates performance overhead.
In Oracle Database 12c, the statistics preference INCREMENTAL_STALENESS controls
how the database determines whether the statistics on a partition or subpartition are
stale. This preference takes the following values:
• USE_STALE_PERCENT
A partition or subpartition is not considered stale if DML changes are less than the
STALE_PERCENT preference specified for the table. The default value of
STALE_PERCENT is 10, which means that if DML causes more than 10% of row
changes, then the table is considered stale.
• USE_LOCKED_STATS
Locked partition or subpartition statistics are not considered stale, regardless of
DML changes.
• NULL (default)
A partition or subpartition is considered stale if it has any DML changes. This
behavior is identical to the Oracle Database 11g behavior. When the default value is
used, statistics gathered in incremental mode are guaranteed to be the same as
statistics gathered in nonincremental mode. When a nondefault value is used,
statistics gathered in incremental mode might be less accurate than those gathered
in nonincremental mode.
You can specify USE_STALE_PERCENT and USE_LOCKED_STATS together. For
example, you can write the following anonymous block:
BEGIN
DBMS_STATS.SET_TABLE_PREFS (
null
, 't'
, 'incremental_staleness'
, 'use_stale_percent, use_locked_stats'
);
END;
Assumptions
This tutorial assumes the following:
• You want to discover how statistics gathering changes depending on the setting for
INCREMENTAL_STALENESS, whether the statistics are locked, and the percentage
of DML changes.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_STATS.SET_TABLE_PREFS
• NOWORKLOAD
The optimizer gathers statistics based on system characteristics only, without
regard to the workload.
• INTERVAL
After the specified number of minutes has passed, the optimizer updates system
statistics either in the data dictionary, or in an alternative table (specified by
stattab). Statistics are based on system activity during the specified interval.
• EXADATA
The system statistics consider the unique capabilities provided by using Exadata,
such as large I/O size and high I/O throughput. The optimizer sets the multiblock
read count and I/O throughput statistics along with CPU speed.
Table 12-4 lists the optimizer system statistics gathered by DBMS_STATS and the
options for gathering or manually setting specific system statistics.
See Also:
Oracle Database PL/SQL Packages and Types Reference for detailed information
on the procedures in the DBMS_STATS package for implementing system
statistics
• The best practice is to capture statistics in the interval of time when the system has
the most common workload. Gathering workload statistics does not generate
additional overhead.
beginning to the end of a workload. The database implements these values through
counters that change when the buffer cache completes synchronous read requests.
Because the counters are in the buffer cache, they include not only I/O delays, but also
waits related to latch contention and task switching. Thus, workload statistics depend
on system activity during the workload window. If system is I/O bound (both latch
contention and I/O throughput), then the statistics promote a less I/O-intensive plan
after the database uses the statistics.
As shown in Figure 12-1, if you gather workload statistics, then the optimizer uses the
mbrc value gathered for workload statistics to estimate the cost of a full table scan.
When gathering workload statistics, the database may not gather the mbrc and
mreadtim values if no table scans occur during serial workloads, as is typical of OLTP
systems. However, full table scans occur frequently on DSS systems. These scans may
run parallel and bypass the buffer cache. In such cases, the database still gathers the
sreadtim because index lookups use the buffer cache.
If the database cannot gather or validate gathered mbrc or mreadtim values, but has
gathered sreadtim and cpuspeed, then the database uses only sreadtim and
cpuspeed for costing. In this case, the optimizer uses the value of the initialization
parameter DB_FILE_MULTIBLOCK_READ_COUNT to cost a full table scan. However, if
DB_FILE_MULTIBLOCK_READ_COUNT is 0 or is not set, then the optimizer uses a
value of 8 for calculating cost.
Use the DBMS_STATS.GATHER_SYSTEM_STATS procedure to gather workload
statistics. The GATHER_SYSTEM_STATS procedure refreshes the data dictionary or a
staging table with statistics for the elapsed period. To set the duration of the collection,
use either of the following techniques:
• Specify START the beginning of the workload window, and then STOP at the end of
the workload window.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
initialization parameter DB_FILE_MULTIBLOCK_READ_COUNT
Assumptions
This tutorial assumes the following:
• The hour between 10 a.m. and 11 a.m. is representative of the daily workload.
The optimizer can now use the workload statistics to generate execution plans
that are effective during the normal daily workload.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_SYSTEM_STATS procedure
Assumptions
This tutorial assumes the following:
• The database application processes OLTP transactions during the day and runs
OLAP reports at night. To gather representative statistics, you collect them during
the day for two hours and then at night for two hours.
6. In the day or evening, import the appropriate statistics into the data dictionary.
For example, during the day you can import the OLTP statistics from the staging
table into the dictionary with the following program:
BEGIN
EXECUTE DBMS_STATS.IMPORT_SYSTEM_STATS (
For example, during the night you can import the OLAP statistics from the
staging table into the dictionary with the following program:
BEGIN
EXECUTE DBMS_STATS.IMPORT_SYSTEM_STATS (
stattab => 'workload_stats'
, statid => 'OLAP'
);
END;
/
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_SYSTEM_STATS procedure
Assumptions
This tutorial assumes that you want to gather noworkload statistics manually.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_SYSTEM_STATS procedure
Assumptions
This tutorial assumes the following:
• You gathered statistics for a specific intensive workload, but no longer want the
optimizer to use these statistics.
• You stored workload statistics in the default location, not in a user-specified table.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.DELETE_SYSTEM_STATS procedure
This chapter explains advanced concepts and tasks relating to optimizer statistics
management, including extended statistics.
This chapter contains the following topics:
See Also:
See Also:
“Dynamic Statistics”
Level When the Optimizer Uses Dynamic Statistics Sample Size (Blocks)
0 Do not use dynamic statistics n/a
10 Use dynamic statistics if the statement meets level 4 criteria. All blocks
Level When the Optimizer Uses Dynamic Statistics Sample Size (Blocks)
11 Use dynamic statistics automatically when the optimizer Automatically
deems it necessary. The resulting statistics are persistent in determined
the statistics repository, making them available to other
queries.
See Also:
Assumptions
This tutorial assumes the following:
• You want correct selectivity estimates for the following query, which has WHERE
clause predicates on two correlated columns:
SELECT *
FROM sh.customers
WHERE cust_city='Los Angeles'
AND cust_state_province='CA';
• The sh.customers table contains 932 rows that meet the conditions in the query.
1. Connect SQL*Plus to the database with the appropriate privileges, and then
explain the execution plan as follows:
EXPLAIN PLAN FOR
SELECT *
FROM sh.customers
WHERE cust_city='Los Angeles'
AND cust_state_province='CA';
The output appears below (the example has been reformatted to fit on the page):
-------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost | Time |
-------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | 53| 9593|53(0)|00:00:01|
| 1| TABLE ACCESS BY INDEX ROWID|CUSTOMERS | 53| 9593|53(0)|00:00:01|
|*2| INDEX RANGE SCAN |CUST_CITY_STATE_IND| 53| 9593| 3(0)|00:00:01|
-------------------------------------------------------------------------------
The columns in the WHERE clause have a real-world correlation, but the optimizer
is not aware that Los Angeles is in California and assumes both predicates reduce
the number of rows returned. Thus, the table contains 932 rows that meet the
conditions, but the optimizer estimates 53, as shown in bold.
If the database had used dynamic statistics for this plan, then the Note section of
the plan output would have indicated this fact. The optimizer did not use
dynamic statistics because the statement executed serially, standard statistics
exist, and the parameter OPTIMIZER_DYNAMIC_SAMPLING is set to the default of
2.
3. Set the dynamic statistics level to 4 in the session using the following statement:
ALTER SESSION SET OPTIMIZER_DYNAMIC_SAMPLING=4;
The new plan shows a more accurate estimate of the number of rows, as shown by
the value 932 in bold:
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 2008213504
---------------------------------------------------------------------------
| Id | Operation | Name |Rows | Bytes |Cost (%CPU)|Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 932 | 271K| 406 (1)| 00:00:05 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 932 | 271K| 406 (1)| 00:00:05 |
---------------------------------------------------------------------------
Note
-----
- dynamic statistics used for this statement (level=4)
The note at the bottom of the plan indicates that the sampling level is 4. The
additional dynamic statistics made the optimizer aware of the real-world
relationship between the cust_city and cust_state_province columns,
thereby enabling it to produce a more accurate estimate for the number of rows:
932 rather than 53.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
OPTIMIZER_DYNAMIC_SAMPLING initialization parameter
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
OPTIMIZER_DYNAMIC_SAMPLING initialization parameter
The top part of Figure 13-1 shows the optimizer gathering statistics for the
sh.customers table and storing them in the data dictionary with pending status.
The bottom part of the diagram shows the optimizer using only published statistics to
process a query of sh.customers.
Data Dictionary
Published
1 0 0 1 1 1 Statistics
0 1 0 0 0 1
Optimizer
0 0 1 0 0 0 Pending
Statistics
1 1 0 0 1 0
Publishing
preferences
set to false
Customers
Table
Data Dictionary
Optimizer Statistics
Optimizer Published
SELECT ... 1 0 0 1 1 1 Statistics
FROM 0 1 0 0 0 1
customers
0 0 1 0 0 0 Pending
Statistics
1 1 0 0 1 0
OPTIMIZER_USE_PENDING_STATISTICS=false
In some cases, the optimizer can use a combination of published and pending
statistics. For example, the database stores both published and pending statistics for
the customers table. For the orders table, the database stores only published
statistics. If OPTIMIZER_USE_PENDING_STATS = true, then the optimizer uses
pending statistics for customers and published statistics for orders. If
OPTIMIZER_USE_PENDING_STATS = false, then the optimizer uses published
statistics for customers and orders.
See Also:
Oracle Database Reference to learn about the
OPTIMIZER_USE_PENDING_STATISTICS initialization parameter
View Description
USER_TAB_STATISTICS Displays optimizer statistics for the tables accessible
to the current user.
View Description
USER_IND_STATISTICS Displays optimizer statistics for the indexes
accessible to the current user.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
Assumptions
This tutorial assumes the following:
• You want to change the preferences for the sh.customers and sh.sales tables
so that newly collected statistics have pending status.
• You want to gather and publish pending statistics on the sh.customers table.
• You gather the pending statistics on the sh.sales table, but decide to delete them
without publishing them.
• You want to change the preferences for the sh.customers and sh.sales tables
so that newly collected statistics are published.
PUBLISH
-------
TRUE
The value true indicates that the database publishes statistics as it gathers them.
Every table uses this value unless a specific table preference has been set.
When using GET_PREFS, you can also specify a schema and table name. The
function returns a table preference if it is set. Otherwise, the function returns the
global preference.
no rows selected
This example shows that the database currently stores no pending statistics for the
sh schema.
Subsequently, when you gather statistics on the customers table, the database
does not automatically publish statistics when the gather job completes. Instead,
the database stores the newly gathered statistics in the
USER_TAB_PENDING_STATS table.
TABLE_NAME NUM_ROWS
------------------------------ ----------
CUSTOMERS 55500
This example shows that the database now stores pending statistics for the
sh.customers table.
8. Run a workload.
The following example changes the email addresses of all customers named Bruce
Chalmers:
UPDATE sh.customers
SET cust_email='[email protected]'
WHERE cust_first_name = 'Bruce'
AND cust_last_name = 'Chalmers';
COMMIT;
The optimizer uses the pending statistics instead of the published statistics when
compiling all SQL statements in this session.
Subsequently, when you gather statistics on the sh.sales table, the database
does not automatically publish statistics when the gather job completes. Instead,
the database stores the statistics in the USER_TAB_PENDING_STATS table.
13. Change the publishing preferences for the sh.customers and sh.sales tables
back to their default setting.
For example, execute the following program:
BEGIN
DBMS_STATS.SET_TABLE_PREFS('sh', 'customers', 'publish', null);
DBMS_STATS.SET_TABLE_PREFS('sh', 'sales', 'publish', null);
END;
/
• Expression statistics
This type of extended statistics improves optimizer estimates when predicates use
expressions, for example, built-in or user-defined functions. An example might be
the UPPER function applied to an employee last name. See “Managing Expression
Statistics”.
Note:
You cannot create extended statistics on virtual columns. See Oracle Database
SQL Language Reference for a list of restrictions on virtual columns.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_
Statistics for
Column Group
DBMS_STATS
Note:
The optimizer uses column group statistics for equality predicates, inlist
predicates, and for estimating the GROUP BY cardinality.
COUNT(*)
----------
3341
Consider an explain plan for a query of customers in the state CA and in the country
with ID 52790 (USA):
EXPLAIN PLAN FOR
SELECT *
FROM sh.customers
WHERE cust_state_province = 'CA'
AND country_id=52790;
Explained.
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1683234692
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 128 | 24192 | 442 (7)| 00:00:06 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 128 | 24192 | 442 (7)| 00:00:06 |
-------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
13 rows selected.
California, but the optimizer does not know that California is in the USA, and so
greatly underestimates cardinality by assuming that both predicates reduce the
number of returned rows.
You can make the optimizer aware of the real-world relationship between values in
country_id and cust_state_province by gathering column group statistics.
These statistics enable the optimizer to give a more accurate cardinality estimate.
See Also:
REPORT_COL_USAGE Generates a report that lists the columns that were seen in
filter predicates, join predicates, and GROUP BY clauses in
the workload.
You can use this function to review column usage
information recorded for a specific table.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
Note:
You can seed column usage from a SQL tuning set (see Managing SQL Tuning
Sets ).
Assumptions
This tutorial assumes the following:
• You want the database to monitor your workload for 5 minutes (300 seconds).
• You want the database to determine which column groups are needed
automatically.
1. Connect SQL*Plus to the database as user sh, and then create the
customers_test table and gather statistics for it:
CONNECT SH/SH
DROP TABLE customers_test;
CREATE TABLE customers_test AS SELECT * FROM customer;
EXEC DBMS_STATS.GATHER_TABLE_STATS(user, 'customers_test');
3. As user sh, run explain plans for two queries in the workload.
The following examples show the explain plans for two queries on the
customers_test table:
EXPLAIN PLAN FOR
SELECT *
FROM customers_test
WHERE cust_city = 'Los Angeles'
AND cust_state_province = 'CA'
AND country_id = 52790;
SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));
SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));
----------------------------------------------------
| Id | Operation | Name | Rows |
----------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | TABLE ACCESS FULL| CUSTOMERS_TEST | 1 |
----------------------------------------------------
8 rows selected.
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 3050654408
-----------------------------------------------------
| Id | Operation | Name | Rows |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 1949 |
| 1 | HASH GROUP BY | | 1949 |
| 2 | TABLE ACCESS FULL| CUSTOMERS_TEST | 55500 |
-----------------------------------------------------
9 rows selected.
The first plan shows a cardinality of 1 row for a query that returns 932 rows. The
second plan shows a cardinality of 1949 rows for a query that returns 145 rows.
4. Optionally, review the column usage information recorded for the table.
Call the DBMS_STATS.REPORT_COL_USAGE function to generate a report:
SET LONG 100000
SET LINES 120
SET PAGES 0
SELECT DBMS_STATS.REPORT_COL_USAGE(user, 'customers_test')
FROM DUAL;
###########################################################################
1. COUNTRY_ID : EQ
2. CUST_CITY : EQ
3. CUST_STATE_PROVINCE : EQ
4. (CUST_CITY, CUST_STATE_PROVINCE,
COUNTRY_ID) : FILTER
5. (CUST_STATE_PROVINCE, COUNTRY_ID) : GROUP_BY
###########################################################################
In the preceding report, the first three columns were used in equality predicates in
the first monitored query:
...
WHERE cust_city = 'Los Angeles'
AND cust_state_province = 'CA'
AND country_id = 52790;
All three columns appeared in the same WHERE clause, so the report shows them
as a group filter. In the second query, two columns appeared in the GROUP BY
clause, so the report labels them as GROUP_BY. The sets of columns in the FILTER
and GROUP_BY report are candidates for column groups.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
Assumptions
This tutorial assumes that you have performed the steps in “Detecting Useful Column
Groups for a Specific Workload”.
1. Create column groups for the customers_test table based on the usage
information captured during the monitoring window.
For example, run the following query:
SELECT DBMS_STATS.CREATE_EXTENDED_STATS(user, 'customers_test') FROM DUAL;
###########################################################################
EXTENSIONS FOR SH.CUSTOMERS_TEST
................................
1. (CUST_CITY, CUST_STATE_PROVINCE,
COUNTRY_ID) :SYS_STUMZ$C3AIHLPBROI#SKA58H_N created
2. (CUST_STATE_PROVINCE, COUNTRY_ID):SYS_STU#S#WF25Z#QAHIHE#MOFFMM_ created
###########################################################################
The database created two column groups for customers_test: one column
group for the filter predicate and one group for the GROUP BY operation.
3. As user sh, run explain plans for two queries in the workload.
Check the USER_TAB_COL_STATISTICS view to determine which additional
statistics were created by the database:
SELECT COLUMN_NAME, NUM_DISTINCT, HISTOGRAM
FROM USER_TAB_COL_STATISTICS
WHERE TABLE_NAME = 'CUSTOMERS_TEST'
ORDER BY 1;
This example shows the two column group names returned from the
DBMS_STATS.CREATE_EXTENDED_STATS function. The column group created
on CUST_CITY, CUST_STATE_PROVINCE, and COUNTRY_ID has a height-
balanced histogram.
SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));
SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));
----------------------------------------------------
| Id | Operation | Name | Rows |
----------------------------------------------------
| 0 | SELECT STATEMENT | | 1093 |
| 1 | TABLE ACCESS FULL| CUSTOMERS_TEST | 1093 |
----------------------------------------------------
8 rows selected.
-----------------------------------------------------
| Id | Operation | Name | Rows |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 145 |
| 1 | HASH GROUP BY | | 145 |
| 2 | TABLE ACCESS FULL| CUSTOMERS_TEST | 55500 |
-----------------------------------------------------
9 rows selected.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
Assumptions
This tutorial assumes the following:
• You want to gather statistics (including histograms) on the entire table and the new
column group.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
Assumptions
This tutorial assumes the following:
• You want to determine the column group name, the number of distinct values, and
whether a histogram has been created for a column group.
EXTENSION_NAME EXTENSION
-----------------------------------------------------------------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_ ("CUST_STATE_PROVINCE","COUNTRY_ID")
3. Query the number of distinct values and find whether a histogram has been
created for a column group.
For example, run the following query:
SELECT e.EXTENSION col_group, t.NUM_DISTINCT, t.HISTOGRAM
FROM USER_STAT_EXTENSIONS e, USER_TAB_COL_STATISTICS t
WHERE e.EXTENSION_NAME=t.COLUMN_NAME
AND e.TABLE_NAME=t.TABLE_NAME
AND t.TABLE_NAME='CUSTOMERS';
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.SHOW_EXTENDED_STATS_NAME function
Assumptions
This tutorial assumes the following:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.DROP_EXTENDED_STATS function
Optimizer
Do
Use Yes expression No Use Default
Expression statistics Column
Statistics exist? Statistics
LOWER(cust_state_province) cust_state_province
Expression Statistics Column Statistics
Optimal Suboptimal
Estimate Estimate
As shown in Figure 13-3, when expression statistics are not available, the optimizer
can produce suboptimal plans.
See Also:
Oracle Database SQL Language Reference to learn about SQL functions
COUNT(*)
----------
3341
Consider the plan for the same query with the LOWER() function applied:
sys@PROD> EXPLAIN PLAN FOR
2 SELECT * FROM sh.customers WHERE LOWER(cust_state_province)='ca';
Explained.
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 2008213504
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 555 | 108K| 406 (1)| 00:00:05 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 555 | 108K| 406 (1)| 00:00:05 |
-------------------------------------------------------------------------------
1 - filter(LOWER("CUST_STATE_PROVINCE")='ca')
• GATHER_TABLE_STATS procedure
Assumptions
This tutorial assumes the following:
• Selectivity estimates are inaccurate for queries of sh.customers that use the
UPPER(cust_state_province) function.
'sh'
, 'customers'
, method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY FOR COLUMNS
(LOWER(cust_state_province)) SIZE SKEWONLY'
);
END;
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GATHER_TABLE_STATS procedure
Assumptions
This tutorial assumes the following:
• You want to determine the column group name, the number of distinct values, and
whether a histogram has been created for a column group.
3. Query the number of distinct values and find whether a histogram has been
created for the expression.
For example, run the following query:
SELECT e.EXTENSION expression, t.NUM_DISTINCT, t.HISTOGRAM
FROM USER_STAT_EXTENSIONS e, USER_TAB_COL_STATISTICS t
WHERE e.EXTENSION_NAME=t.COLUMN_NAME
AND e.TABLE_NAME=t.TABLE_NAME
AND t.TABLE_NAME='CUSTOMERS';
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.SHOW_EXTENDED_STATS_NAME procedure
Assumptions
This tutorial assumes the following:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.DROP_EXTENDED_STATS procedure
Locking Statistics
The DBMS_STATS package provides two procedures for locking statistics:
LOCK_SCHEMA_STATS and LOCK_TABLE_STATS.
Assumptions
This tutorial assumes the following:
• You want to prevent the oe.orders table statistics and hr schema statistics from
changing.
To lock statistics:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.LOCK_TABLE_STATS procedure
Unlocking Statistics
The DBMS_STATS package provides two procedures for unlocking statistics:
UNLOCK_SCHEMA_STATS and UNLOCK_TABLE_STATS.
Assumptions
This tutorial assumes the following:
To unlock statistics:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.UNLOCK_TABLE_STATS procedure
the current statistics may be causing the optimizer to generate suboptimal plans. On
August 25, the administrator restores the statistics collected on August 10.
• You want to recover older versions of the statistics. For example, you want to
restore the optimizer behavior to an earlier date.
• You want the database to manage the retention and purging of statistics histories.
Export statistics rather than restoring them in the following situations:
• You want to experiment with multiple sets of statistics and change the values back
and forth.
• You want to move the statistics from one database to another database. For
example, moving statistics from a production system to a test system.
• You want to preserve a known set of statistics for a longer period than the desired
retention date for restoring statistics.
See Also:
Oracle Database PL/SQL Packages and Types Reference for an overview of the
procedures for restoring and importing statistics
• Old versions of statistics are not stored when the ANALYZE command has been
used for collecting statistics.
Procedure Description
Dictionary views display the time of statistics modifications. You can use the
following views to determine the time stamp to be use for the restore operation:
Assumptions
This tutorial assumes the following:
• After the most recent statistics collection for the oe.orders table, the optimizer
began choosing suboptimal plans for queries of this table.
• You want to restore the statistics from before the most recent statistics collection to
see if the plans improve.
You can specify any date between 8/10 and 8/20 because DBMS_STATS restores
statistics as of the specified time.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about the
DBMS_STATS.RESTORE_TABLE_STATS procedure
• GET_STATS_HISTORY_RETENTION
This function can retrieve the current statistics history retention value.
• GET_STATS_HISTORY_AVAILABILITY
This function retrieves the oldest time stamp when statistics history is available.
Users cannot restore statistics to a time stamp older than the oldest time stamp.
1. Start SQL*Plus and connect to the database with the necessary privileges.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.GET_STATS_HISTORY_RETENTION procedure
Prerequisites
To run this procedure, you must have either the SYSDBA privilege, or both the
ANALYZE ANY DICTIONARY and ANALYZE ANY system privileges.
Assumptions
This tutorial assumes the following:
• You run queries annually as part of an annual report. To keep the statistics history
for more than 365 days so that you have access to last year's plan (in case a
suboptimal plan occurs now), you set the retention period to 366 days.
1. Start SQL*Plus and connect to the database with the necessary privileges.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.ALTER_STATS_HISTORY_RETENTION procedure
Prerequisites
To run this procedure, you must have either the SYSDBA privilege, or both the
ANALYZE ANY DICTIONARY and ANALYZE ANY system privileges.
Assumptions
This tutorial assumes that you want to purge statistics more than one week old.
1. Start SQL*Plus and connect to the database with the necessary privileges.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.PURGE_STATS procedure
Production Test
Database Database
1. In the production database, copy the statistics from the data dictionary to a
staging table using DBMS_STATS.EXPORT_SCHEMA_STATS.
2. Export the statistics from the staging table to a .dmp file using Oracle Data Pump.
3. Transfer the .dmp file from the production host to the test host using a transfer
tool such as ftp.
4. In the test database, import the statistics from the .dmp file to a staging table
using Oracle Data Pump.
5. Copy the statistics from the staging table to the data dictionary using
DBMS_STATS.IMPORT_SCHEMA_STATS.
• Before exporting statistics, you must create a table to hold the statistics. The
procedure DBMS_STATS.CREATE_STAT_TABLE creates the statistics table.
• The optimizer does not use statistics stored in a user-owned table. The only
statistics used by the optimizer are the statistics stored in the data dictionary. To
make the optimizer use statistics in user-defined tables, import these statistics into
the data dictionary using the DBMS_STATS import procedure.
• The Data Pump Export and Import utilities export and import optimizer statistics
from the database along with the table. When a column has system-generated
names, Original Export (exp) does not export statistics with the data, but this
restriction does not apply to Data Pump Export.
Note:
Assumptions
This tutorial assumes the following:
• You intend to use Oracle Data Pump to export and import table opt_stats.
1. On the production host, start SQL*Plus and connect to the production database as
administrator dba1.
END;
/
5. Use Oracle Data Pump to export the contents of the statistics table.
For example, run the expdp command at the operating schema prompt:
expdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=stat.dmp TABLES=opt_stats
7. Log in to the test host, and then use Oracle Data Pump to import the contents of
the statistics table.
For example, run the impdp command at the operating schema prompt:
impdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=stat.dmp TABLES=opt_stats
8. On the test host, start SQL*Plus and connect to the test database as administrator
dba1.
9. Use DBMS_STATS to import statistics from the user statistics table and store them
in the data dictionary.
The following PL/SQL program imports schema statistics from table opt_stats
into the data dictionary:
BEGIN
DBMS_STATS.IMPORT_SCHEMA_STATS(
ownname => 'dba1'
, stattab => 'opt_stats'
);
END;
/
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS.CREATE_STAT_TABLE function
• Oracle Database PL/SQL Packages and Types Reference for an overview of the
statistics transfer functions
Function Description
Function Description
Assumptions
This tutorial assumes that you want to generate an HTML report of the objects that
would be affected by running GATHER_SCHEMA_STATS on the oe schema.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_STATS
Function Description
Function Description
Assumptions
This tutorial assumes that you want to generate HTML reports of the following:
);
END;
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn more about
DBMS_STATS
Procedure Description
Prerequisites
You must have the Administer SQL Management Object privilege to execute the
DBMS_SPD APIs.
Assumptions
This tutorial assumes that you want to do the following:
3. Query the data dictionary for information about existing directives in the sh
schema.
Example 13-1 queries the data dictionary for information about the directive.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE procedure
User
Optimizer
The overlapping squares in Figure 14-1 show that SQL plan management uses both
initialization parameters and hints. SQL profiles also technically include hints.
You can use the following techniques to influence the optimizer:
• Initialization parameters
Parameters influence many types of optimizer behavior at the database instance
and session level. The most important parameters are covered in “Influencing the
Optimizer with Initialization Parameters”.
• Hints
A hint is a commented instruction in a SQL statement. Hints control a wide range
of behavior. See “Influencing the Optimizer with Hints”.
• DBMS_STATS
This package updates and manages optimizer statistics. The more accurate the
statistics, the better the optimizer estimates.
This chapter does not cover DBMS_STATS. See Managing Optimizer Statistics: Basic
Topics.
• SQL profiles
A SQL profile is a database object that contains auxiliary statistics specific to a SQL
statement. Conceptually, a SQL profile is to a SQL statement what a set of object-
level statistics is to a table or index. A SQL profile can correct suboptimal optimizer
estimates discovered during SQL tuning.
This chapter does not cover SQL profiles. See Managing SQL Profiles .
Note:
A stored outline is a legacy technique that serve a similar purpose to SQL plan
baselines. See Migrating Stored Outlines to SQL Plan Baselines to learn how to
migrate stored outlines to SQL plan baselines.
In some cases, multiple techniques optimize the same behavior. For example, you can
set optimizer goals using both initialization parameters and hints.
See Also:
• Oracle Database Performance Tuning Guide to learn how to tune the query
result cache
Caution:
Assumptions
This tutorial assumes the following:
• You recently upgraded the database from Oracle Database 10g Release 2 (10.2.0.5)
to Oracle Database 11g Release 2 (11.2.0.2).
• You want to preserve the optimizer behavior from the earlier release.
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the current optimizer features settings.
For example, run the following SQL*Plus command:
SQL> SHOW PARAMETER optimizer_features_enable
The preceding statement restores the optimizer functionality that existed in Oracle
Database 10g Release 2 (10.2.0.5).
See Also:
Oracle Database Reference to learn about optimizer features enabled when you
set OPTIMIZER_FEATURES_ENABLE to different release values
time is less important because the user does not examine the results of individual
statements while the application is running.
Assumptions
This tutorial assumes the following:
• The primary application is interactive, so you want to set the optimizer goal for the
database instance to minimize response time.
• For the current session only, you want to run a report and optimize for throughput.
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the current optimizer mode.
For example, run the following SQL*Plus command:
dba1@PROD> SHOW PARAMETER OPTIMIZER_MODE
3. At the session level only, optimize for throughput before running a report.
For example, run the following SQL statement to configure only this session to
optimize for throughput:
SQL> ALTER SESSION SET OPTIMIZER_MODE='ALL_ROWS';
See Also:
Oracle Database Reference to learn about the OPTIMIZER_MODE initialization
parameter
Assumptions
This tutorial assumes the following:
• You want to disable adaptive optimization for testing purposes so that the database
generates only reports.
1. Connect SQL*Plus to the database as SYSTEM, and then query the current settings.
For example, run the following SQL*Plus command:
SHOW PARAMETER OPTIMIZER_ADAPTIVE_REPORTING_ONLY
3. Run a query.
Note:
The format argument that you pass to DBMS_XPLAN.DISPLAY_CURSOR must
include the +REPORT parameter. When this parameter is set, the report shows
the plan the optimizer would have picked if automatic reoptimization had
been enabled.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
+REPORT parameter of the DBMS_XPLAN.DISPLAY_CURSOR function
Note:
Oracle Database SQL Language Reference contains a complete reference for all
SQL hints
Optimizer
Generate Plan
Id Operation Name
0 SELECT STATEMENT
1 TABLE ACCESS BY INDEX ROWID EMPLOYEES
*2 INDEX UNIQUE SCAN EMP_DEP_IX
The advantage of hints is that they enable you to make decisions normally made by
the optimizer. In a test environment, hints are useful for testing the performance of a
specific access path. For example, you may know that an index is more selective for
certain queries, as in Figure 14-2. In this case, the hint may cause the optimizer to
generate a better plan.
The disadvantage of hints is the extra code that you must manage, check, and control.
Hints were introduced in Oracle7, when users had little recourse if the optimizer
generated suboptimal plans. Because changes in the database and host environment
can make hints obsolete or have negative consequences, a good practice is to test using
hints, but use other techniques to manage execution plans.
Oracle provides several tools, including SQL Tuning Advisor, SQL plan management,
and SQL Performance Analyzer, to address performance problems not solved by the
optimizer. Oracle strongly recommends that you use these tools instead of hints
because they provide fresh solutions as the data and database environment change.
Types of Hints
Hints fall into the following types:
• Single-table
Single-table hints are specified on one table or view. INDEX and USE_NL are
examples of single-table hints. The following statement uses a single-table hint:
SELECT /*+ INDEX (employees emp_department_ix)*/ employee_id, department_id
FROM employees
WHERE department_id > 50;
• Multi-table
Multi-table hints are like single-table hints except that the hint can specify multiple
tables or views. LEADING is an example of a multi-table hint. The following
statement uses a multi-table hint:
SELECT /*+ LEADING(e j) */ *
FROM employees e, departments d, job_history j
WHERE e.department_id = d.department_id
AND e.hire_date = j.start_date;
Note:
• Query block
Query block hints operate on single query blocks. STAR_TRANSFORMATION and
UNNEST are examples of query block hints. The following statement uses a query
block hint:
SELECT /*+ STAR_TRANSFORMATION */ s.time_id, s.prod_id, s.channel_id
FROM sales s, times t, products p, channels c
WHERE s.time_id = t.time_id AND s.prod_id = p.prod_id
AND s.channel_id = c.channel_id AND c.channel_desc = 'Tele Sales';
• Statement
Statement hints apply to the entire SQL statement. ALL_ROWS is an example of a
statement hint. The following statement uses a statement hint:
SELECT /*+ ALL_ROWS */ * FROM sales;
Scope of Hints
When you specify a hint, it optimizes only the statement block in which it appears,
overriding any instance-level or session-level parameters. A statement block is one of
the following:
The preceding statement has two blocks, one for each component query. Hints in the
first component query apply only to its optimization, not to the optimization of the
second component query. For example, in the first week of 2015 you query current
year and last year sales. You apply FIRST_ROWS(10) to the query of last year's (2014)
sales and the ALL_ROWS hint to the query of this year's (2015) sales.
See Also:
The database ignores incorrectly specified hints. The database also ignores
combinations of conflicting hints, even if these hints are correctly specified. If one hint
is incorrectly specified, but a hint in the same comment is correctly specified, then the
database considers the correct hint.
Caution:
The database does not issue error messages for hints that it ignores.
A statement block can have only one comment containing hints, but it can contain
many space-separated hints. For example, a complex query may include multiple table
joins. If you specify only the INDEX hint for a specified table, then the optimizer must
determine the remaining access paths and corresponding join methods. The optimizer
may not use the INDEX hint because the join methods and access paths prevent it.
Example 14-2 uses multiple hints to specify the exact join order.
See Also:
Oracle Database SQL Language Reference to learn about the syntax rules for
comments and hints
• Avoid a full table scan when an index retrieves the requested rows more efficiently.
• Avoid using an index that fetches many rows from the driving table when you can
use a different index that fetches a small number of rows.
• Choose the join order so that you join fewer rows to tables later in the join order.
The following example shows how to tune join order effectively:
SELECT *
FROM taba a, tabb b, tabc c
WHERE a.acol BETWEEN 100 AND 200
1. Choose the driving table and the driving index (if any).
Each of the first three conditions in the previous example is a filter condition that
applies to a single table. The last two conditions are join conditions.
Filter conditions dominate the choice of driving table and index. In general, the
driving table contains the filter condition that eliminates the highest percentage of
rows. Thus, because the range of 100 to 200 is narrow compared with the range of
acol, but the ranges of 10000 and 20000 are relatively large, taba is the driving
table, all else being equal.
With nested loops joins, the joins occur through the join indexes, which are the
indexes on the primary or foreign keys used to connect that table to an earlier
table in the join tree. Rarely do you use the indexes on the non-join conditions,
except for the driving table. Thus, after taba is chosen as the driving table, use
the indexes on b.key1 and c.key2 to drive into tabb and tabc, respectively.
2. Choose the best join order, driving to the best unused filters earliest.
You can reduce the work of the following join by first joining to the table with the
best still-unused filter. Thus, if bcol BETWEEN ... is more restrictive (rejects a
higher percentage of the rows) than ccol BETWEEN ..., then the last join becomes
easier (with fewer rows) if tabb is joined before tabc.
3. You can use the ORDERED or STAR hint to force the join order.
See Also:
• About Cursors
About Cursors
A private SQL area holds information about a parsed SQL statement and other
session-specific information for processing. When a server process executes SQL or
PL/SQL code, the process uses the private SQL area to store bind variable values,
query execution state information, and query execution work areas. The private SQL
areas for each execution of a statement are not shared and may contain different
values and data.
A cursor is a name or handle to a specific private SQL area. The cursor contains
session-specific state information such as bind variable values and result sets.
As shown in the following graphic, you can think of a cursor as a pointer on the client
side and as a state on the server side. Because cursors are closely associated with
private SQL areas, the terms are sometimes used interchangeably.
PGA
SQL Work Areas Server
Process
Session Memory Private SQL Area
Cursor
Data Area
Client
Pointer Process
Instance
Shared Pool
Library Cache
Shared SQL Area Private
SELECT * FROM SQL Area
employees (Shared
Server Only)
PGA PGA
Server SQL Work Areas Server SQL Work Areas
Process Process
Session Memory Private SQL Area Session Memory Private SQL Area
Client Client
Process Process
2. If no matching hash value exists, then the SQL statement does not currently exist
in the shared pool, so the database performs a hard parse.
3. The database looks for a matching hash value for an existing SQL statement in the
shared pool. The following options are possible:
Usually, SQL statements that differ only in literals cannot use the same shared
SQL area. For example, the following statements do not resolve to the same
SQL area:
SELECT count(1) FROM employees WHERE manager_id = 121;
SELECT count(1) FROM employees WHERE manager_id = 247;
The only exception to this rule is when the parameter CURSOR_SHARING has
been set to FORCE, in which case similar statements can share SQL areas. The
costs involved in using CURSOR_SHARING are explained in “Do Not Use
CURSOR_SHARING = FORCE as a Permanent Fix”.
5. The database determines whether bind variables in the SQL statements match in
name, data type, and length.
For example, the following statements cannot use the same shared SQL area
because the bind variable names differ:
SELECT * FROM employees WHERE department_id = :department_id;
SELECT * FROM employees WHERE department_id = :dept_id;
See Also:
COUNT(*)
----------
319
COUNT(*)
----------
319
COUNT(*)
----------
155500
The following query of V$SQL indicates the two parents. The statement with the SQL
ID of 8h916vv2yw400, which is the lowercase “c” version of the statement, has one
parent cursor and two child cursors: child 0 and child 1. The statement with the SQL
ID of 5rn2uxjtpz0wd, which is the uppercase “c” version of the statement, has a
different parent cursor and only one child cursor: child 0.
SQL> CONNECT SYSTEM@inst1
Enter password: *******
Connected.
In the preceding results, the CHILD# of the bottom two statements is different (0 and
1), even though the SQL_ID is the same. This means that the statements have the same
parent cursor, but different child cursors. In contrast, the statement with the SQL_ID
of 5bzhzpaa0wy9m has one parent and one child (CHILD# of 0). All three SQL
statements use the same execution plan, as indicated by identical values in the
PLAN_HASH_VALUE column.
• Accessing the library cache and data dictionary cache numerous times to check the
data dictionary
An especially resource-intensive aspect of hard parsing is accessing the library cache
and data dictionary cache numerous times to check the data dictionary. When the
database accesses these areas, it uses a serialization device called a latch on required
objects so that their definition does not change during the check. Latch contention
increases statement execution time and decreases concurrency.
For all of the preceding reasons, the CPU and memory overhead of hard parses can
create serious performance problems. The problems are especially evident in web
applications that accept user input from a form, and then generate SQL statements
dynamically. The Real-World Performance group strongly recommends reducing hard
parsing as much as possible.
Video:
RWP #3: Connection Pools and Hard Parsing
hard parse count to 49, but the second execution does not change the hard parse
count, which means that Oracle Database reused application code.
SQL> ALTER SYSTEM FLUSH SHARED_POOL;
System altered.
NAME VALUE
------------------ ----------
parse count (hard) 48
COUNT(*)
----------
0
NAME VALUE
------------------ ----------
parse count (hard) 49
COUNT(*)
----------
0
NAME VALUE
------------------ ----------
parse count (hard) 49
The following query shows the directory location of the trace files
SQL> SET LINESIZE 120
COLUMN value FORMAT A80
SELECT value
FROM v$diag_info
WHERE name = 'Default Trace File';
VALUE
--------------------------------------------------------------------------------
/disk1/oracle/log/diag/rdbms/orcl/orcl/trace/orcl_ora_23054.trc
You can search this directory for the trace file that you generated:
% ls *emp_stmt.trc
orcl_ora_17950_emp_stmt.trc
Use TKPROF to format the trace file, and then open the formatted file:
% tkprof orcl_ora_17950_emp_stmt.trc emp.out; vi emp.out
The formatted trace file contains the parse information for the query of
hr.employees.
SQL ID: brmjpfs7dcnub Plan Hash: 1445457117
SELECT *
FROM
hr.employees
A library cache miss indicates a hard parse. Performing the same steps for a second
execution of the same statement produces the following trace output, which shows no
library cache misses:
SQL ID: brmjpfs7dcnub Plan Hash: 1445457117
SELECT *
FROM
hr.employees
• Applications that concatenate literals input by an end user are prone to SQL
injection attacks. Only rewriting the applications to use bind variables eliminates
this threat (see “Do Not Use CURSOR_SHARING = FORCE as a Permanent Fix”).
• If every statement is hard parsed, then cursors are not shared, and so the database
must consume more memory to create the cursors.
• Oracle Database must latch the shared pool and library cache when hard parsing.
As the number of hard parses increases, so does the number of processes waiting to
latch the shared pool. This situation decreases concurrency and increases
contention.
Video:
The following query of V$SQLAREA shows that the three statements require three
different parent cursors. As shown by VERSION_COUNT, each parent cursor requires
its own child cursor.
COL SQL_TEXT FORMAT a30
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%';
• Applications that use bind variables are not vulnerable to the same SQL injection
attacks as applications that use literals.
• When identical statements use bind variables, Oracle Database can take advantage
of cursor sharing, and share the plan and other information when different values
are bound to the same statement.
• Oracle Database avoids the overhead of latching the shared pool and library cache
required for hard parsing.
Video:
RWP #4: Bind Variables and Soft Parsing
The VERSION_COUNT value of 1 indicates that the database reused the same child
cursor rather than creating three separate child cursors. Using a bind variable made
this reuse possible.
The database hard parsed all three statements, which were not identical. The
DISPLAY_CURSOR output, which has been edited for clarity, shows that the optimizer
chose the same nested loops plan for the first two statements, but a full table scan plan
for the statement using literal 165:
SQL_ID cn5250y0nqpym, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101
-------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
-
| 0| SELECT STATEMENT | | | |2 (100)| |
| 1| SORT AGGREGATE | |1 | 8 | | |
| 2| TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1 | 8 |2 (0) | 00:00:01 |
|*3| INDEX RANGE SCAN | EMP_EMP_ID_PK |1 | |1 (0) | 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<101)
-------------------------------------------------------------------------------------
|Id| Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |2 (100)| |
| 1| SORT AGGREGATE | |1 | 8 | | |
| 2| TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |20|160|2 (0) | 00:00:01 |
|*3| INDEX RANGE SCAN | EMP_EMP_ID_PK |20| |1 (0) | 00:00:01 |
-------------------------------------------------------------------------------------
3 - access("EMPLOYEE_ID"<120)
-------------------------------------------------------------------------
| Id | Operation | Name |Rows| Bytes |Cost(%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| EMPLOYEES | 66 | 528 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------
2 - filter("EMPLOYEE_ID"<165)
The preceding output shows that the optimizer considers a full table scan more
efficient than an index scan for the query that returns more rows.
Example 15-8 Bind Variables Result in Cursor Reuse
This example rewrites the queries executed in Example 15-7 to use bind variables
instead of literals. You bind the same values (101, 120, and 165) to the bind
variable :emp_id, and then display the execution plans for each:
VAR emp_id NUMBER
The DISPLAY_CURSOR output shows that the optimizer chose exactly the same plan
for all three statements:
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id
-------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost (%CPU)|Time|
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |2 (100)| |
| 1 | SORT AGGREGATE | |1|8 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1|8 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK |1| | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
3 - access("EMPLOYEE_ID"<:EMP_ID)
In contrast, when the preceding statements were executed with literals, the optimizer
chose a lower-cost full table scan when the employee ID value was 165. This is the
problem solved by adaptive cursor sharing (see “Adaptive Cursor Sharing”).
• EXACT
This is the default value. The database enables only textually identical statements
to share a cursor. The database does not attempt to replace literal values with
system-generated bind variables. In this case, the optimizer generates a plan for
each statement based on the literal value.
• FORCE
The database replaces all literals with system-generated bind variables. For
statements that are identical after the bind variables replace the literals, the
optimizer uses the same plan.
Note:
You can set CURSOR_SHARING at the system or session level, or use the
CURSOR_SHARING_EXACT hint at the statement level.
See Also:
Note:
If a statement uses an ORDER BY clause, then the database does not perform
literal replacement in the clause because it is not semantically correct to
consider the constant column number as a literal. The column number in the
ORDER BY clause affects the query plan and execution, so the database cannot
share two cursors having different column numbers.
When CURSOR_SHARING is set to FORCE, the database performs the following steps
during the parse:
1. Copies all literals in the statement to the PGA, and replaces them with system-
generated bind variables
For example, an application could process the following statement:
The optimizer replaces literals, including the literals in the SUBSTR function, as
follows:
SELECT SUBSTR(last_name, :"SYS_B_0", :"SYS_B_1"), SUM(salary)
FROM hr.employees
WHERE employee_id < :"SYS_B_2" GROUP BY last_name
2. Searches for an identical statement (same SQL hash value) in the shared pool
If an identical statement is not found, then the database performs a hard parse.
Otherwise, the database proceeds to the next step.
The following DISPLAY_CURSOR output, edited for readability, shows that all three
statements used the same plan. The optimizer chose the plan, an index range scan,
because it peeked at the first value (101) bound to the system bind variable, and
picked this plan as the best for all values. In fact, this plan is not the best plan for all
values. When the value is 165, a full table scan is more efficient.
SQL_ID cxx8n1cxr9khn, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :"SYS_B_0"
-------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |2 (100)| |
| 1 | SORT AGGREGATE | |1 | 8 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1 | 8 |2 (0) |00:00:01|
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK |1 | |1 (0) |00:00:01|
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<101)
A query of V$SQLAREA confirms that Oracle Database replaced with the literal with
system bind variable :”SYS_B_0”, and created one parent and one child cursor
(VERSION_COUNT=1) for all three statements, which means that all executions shared
the same plan.
COL SQL_TEXT FORMAT a36
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE eee_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%';
See Also:
• “Private and Shared SQL Areas” for more details on the various checks
performed
• Bind-Sensitive Cursors
• Bind-Aware Cursors
• Cursor Merging
In adaptive cursor sharing, the database monitors data accessed over time for different
bind values, ensuring the optimal choice of cursor for a specific bind value. For
example, the optimizer might choose one plan for bind value 10 and a different plan
for bind value 50. Cursor sharing is "adaptive" because the cursor adapts its behavior
so that the optimizer does not always choose the same plan for each execution or bind
variable value. Thus, the optimizer automatically detects when different execution of a
statement would benefit from different execution plans.
Note:
Also assume in this example that a histogram exists on at least one of the columns in
the predicate. The database processes this statement as follows:
1. The application issues the statement for the first time, which causes a hard parse.
During the parse, the database performs the following tasks:
• Stores metadata about the predicate, including the cardinality of the bound
values (in this example, assume that only 5 rows were returned).
• Creates an execution plan (in this example, a nested loops join) based on the
peeked values.
2. The database executes the cursor, storing the bind values and execution statistics
in the cursor.
3. The application issues the statement a second time, using different bind variables,
causing the database to perform a soft parse, and find the matching cursor in the
library cache.
a. The database compares the execution statistics for the second execution with
the first-execution statistics.
b. The database observes the pattern of statistics over all previous executions,
and then decides whether to mark the cursor as a bind-aware cursor. In this
example, assume that the database decides the cursor is bind-aware.
6. The application issues the statement a third time, using different bind variables,
which causes a soft parse. Because the cursor is bind-aware, the database does the
following:
• Determines whether the cardinality of the new values falls within the same
range as the stored cardinality. In this example, the cardinality is similar: 8
rows instead of 5 rows.
8. The application issues the statement a fourth time, using different bind variables,
causing a soft parse. Because the cursor is bind-aware, the database does the
following:
• Determines whether the cardinality of the new values falls within the same
range as the stored cardinality. In this example, the cardinality is vastly
different: 102 rows (in a table with 107 rows) instead of 5 rows.
9. The database performs a hard parse. As a result, the database does the following:
• Creates a new child cursor with a second execution plan (in this example, a
hash join)
• Stores metadata about the predicate, including the cardinality of the bound
values, in the cursor
11. The database stores the new bind values and execution statistics in the new child
cursor.
12. The application issues the statement a fifth time, using different bind variables,
which causes a soft parse. Because the cursor is bind-aware, the database does the
following:
• Determines whether the cardinality of the new values falls within the same
range as the stored cardinality. In this example, the cardinality is 20.
13. The database performs a hard parse. As a result, the database does the following:
a. Creates a new child cursor with a third execution plan (in this example, a
nested loops join)
b. Determines that this nested loops join execution plan is the same as the nested
loops execution plan used for the first execution of the statement
c. Merges the two child cursors containing nested loop plans, which involves
storing the combined cardinality statistics into one child cursor, and deleting
the other one
14. The database executes the cursor using the nested loops execution plan.
Bind-Sensitive Cursors
A bind-sensitive cursor is a cursor whose optimal plan may depend on the value of a
bind variable. The database has examined the bind value when computing cardinality,
and considers the query “sensitive” to plan changes based on different bind values.
The database monitors the behavior of a bind-sensitive cursor that uses different bind
values to determine whether a different plan is beneficial.
The optimizer uses the following criteria to decide whether a cursor is bind-sensitive:
• The optimizer has peeked at the bind values to generate cardinality estimates.
DECLARE
v_counter NUMBER(7) := 1000;
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO hr.employees
VALUES (v_counter,null,'Doe','[email protected]',null,'07-
JUN-02','AC_ACCOUNT',null,null,null,50);
v_counter := v_counter + 1;
END LOOP;
END;
/
COMMIT;
FROM DBA_TAB_COLS
WHERE OWNER = 'HR'
AND TABLE_NAME = 'EMPLOYEES'
AND COLUMN_NAME = 'DEPARTMENT_ID';
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
1 200
The optimizer chooses an index range scan, as expected for such a low-cardinality
query:
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a9upgaqqj7bn5, child number 0
-------------------------------------
select COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id
-------------------------------------------------------------------------------------
| Id| Operation | Name |Rows|Bytes|Cost (%CPU)|Time |
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |2(100)| |
| 1| SORT AGGREGATE | |1 |8 | | |
| 2| TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1 |8 |2 (0)|00:00:01|
|*3| INDEX RANGE SCAN | EMP_DEPARTMENT_IX |1 | |1 (0)|00:00:01|
-------------------------------------------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
The preceding output shows one child cursor that has been executed once for the low-
cardinality query. The cursor has been marked bind-sensitive because the optimizer
believes the optimal plan may depend on the value of the bind variable.
When a cursor is marked bind-sensitive, Oracle Database monitors the behavior of the
cursor using different bind values, to determine whether a different plan for different
bind values is more efficient. The database marked this cursor bind-sensitive because
the optimizer used the histogram on the department_id column to compute the
selectivity of the predicate WHERE department_id = :dept_id. Because the
presence of the histogram indicates that the column is skewed, different values of the
bind variable may require different plans.
Example 15-12 High-Cardinality Query
This example continues the example in Example 15-11. The following code re-executes
the same query using the value 50, which occupies 99.9% of the rows:
EXEC :dept_id := 50;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045 100999
Even though such an unselective query would be more efficient with a full table scan,
the optimizer chooses the same index range scan used for department_id=10. This
reason is that the database assumes that the existing plan in the cursor can be shared:
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a9upgaqqj7bn5, child number 0
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id
-------------------------------------------------------------------------------------
| Id| Operation | Name |Rows|Bytes|Cost (%CPU)|Time |
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |2(100)| |
| 1| SORT AGGREGATE | |1 |8 | | |
| 2| TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1 |8 |2 (0)|00:00:01|
|*3| INDEX RANGE SCAN | EMP_DEPARTMENT_IX |1 | |1 (0)|00:00:01|
-------------------------------------------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
A query of V$SQL shows that the child cursor has now been executed twice:
SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHAREABLE
FROM V$SQL
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%';
At this stage, the optimizer has not yet marked the cursor as bind-aware.
See Also:
Bind-Aware Cursors
A bind-aware cursor is a bind-sensitive cursor that is eligible to use different plans for
different bind values. After a cursor has been made bind-aware, the optimizer chooses
plans for future executions based on the bind value and its cardinality estimate. Thus,
“bind-aware” means essentially “best plan for the current bind value.”
When a statement with a bind-sensitive cursor executes, the optimizer uses an internal
algorithm to determine whether to mark the cursor bind-aware. The decision depends
on whether the cursor produces significantly different data access patterns for
different bind values, resulting in a performance cost that differs from expectations.
If the database marks the cursor bind-aware, then the next time that the cursor
executes the database does the following:
• Marks the original cursor generated for the statement as not sharable (V
$SQL.IS_SHAREABLE is N). The original cursor is no longer usable and is eligible
to age out of the library cache
When the same query repeatedly executes with different bind values, the database
adds new bind values to the “signature” of the SQL statement (which includes the
optimizer environment, NLS settings, and so on), and categorizes the values. The
database examines the bind values, and considers whether the current bind value
results in a significantly different data volume, or whether an existing plan is
sufficient. The database does not need to create a new plan for each new value.
Consider a scenario in which you execute a statement with 12 distinct bind values
(executing each distinct value twice), which causes the database to trigger 5 hard
parses, and create 2 additional plans. Because the database performs 5 hard parses, it
creates 5 new child cursors, even though some cursors have the same execution plan
as existing cursors. The database marks the superfluous cursors as not usable, which
means these cursors eventually age out of the library cache.
During the initial hard parses, the optimizer is essentially mapping out the
relationship between bind values and the appropriate execution plan. After this initial
period, the database eventually reaches a steady state. Executing with a new bind
value results in picking the best child cursor in the cache, without requiring a hard
parse. Thus, the number of parses does not scale with the number of different bind
values.
Example 15-13 Bind-Aware Cursors
This example continues the example in “Bind-Sensitive Cursors”. The following code
issues a second query employees with the bind variable set to 50:
EXEC :dept_id := 50;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045 100999
During the first two executions, the database was monitoring the behavior of the
queries, and determined that the different bind values caused the queries to differ
significantly in cardinality. Based on this difference, the database adapts its behavior
so that the same plan is not always shared for this query. Thus, the optimizer
generates a new plan based on the current bind value, which is 50:
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a9upgaqqj7bn5, child number 1
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost(%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |254 (100)| |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| EMPLOYEES | 100K | 781K |254 (15)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("DEPARTMENT_ID"=:DEPT_ID)
The preceding output shows that the database created an additional child cursor
(CHILD# of 1). Cursor 0 is now marked as not shareable. Cursor 1 shows a number of
buffers gets lower than cursor 0, and is marked both bind-sensitive and bind-aware. A
bind-aware cursor may use different plans for different bind values, depending on the
selectivity of the predicates containing the bind variable.
Example 15-14 Bind-Aware Cursors: Choosing the Optimal Plan
This example continues the example in “Example 15-13”. The following code executes
the same employees query with the value of 10, which has extremely low cardinality
(only one row):
EXEC :dept_id := 10;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
1 200
The following output shows that the optimizer picked the best plan, which is an index
scan, based on the low cardinality estimate for the current bind value of 10:
SQL> SELECT * from TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID a9upgaqqj7bn5, child number 2
-------------------------------------
select COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id
-------------------------------------------------------------------------------------
| Id| Operation | Name |Rows|Bytes|Cost (%CPU)|Time |
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | |2(100)| |
| 1| SORT AGGREGATE | |1 |8 | | |
| 2| TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1 |8 |2 (0)|00:00:01|
|*3| INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1| |1 (0)|00:00:01|
-------------------------------------------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
The V$SQL output now shows that three child cursors exist:
SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHAREABLE
FROM V$SQL
The database discarded the original cursor (CHILD# of 0) when the cursor switched to
bind-aware mode. This is a one-time overhead. The database marked cursor 0 as not
shareable (SHAREABLE is N), which means that this cursor is unusable and will be
among the first to age out of the cursor cache.
See Also:
Cursor Merging
If the optimizer creates a plan for a bind-aware cursor, and if this plan is the same as
an existing cursor, then the optimizer can perform cursor merging. In this case, the
database merges cursors to save space in the library cache. The database increases the
selectivity range for the cursor to include the selectivity of the new bind value.
When a query uses a new bind variable, the optimizer tries to find a cursor that it
thinks is a good fit based on similarity in the selectivity of the bind value. If the
database cannot find such a cursor, then it creates a new one (see Example 15-10). If
the plan for the new cursor is the same as one of the existing cursors, then the database
merges the two cursors to save space in the library cache. The merge results in the
database marking one cursor as not shareable. If the library cache is under space
pressure, then the database ages out the non-shareable cursor first.
contains the text of the predicates, and the low and high values for the selectivity
ranges.
See Also:
Oracle Database Reference to learn about V$SQL and its related views
Video:
See RWP #3: Connection Pools and Hard Parsing for a demo illustrating the
performance problems caused by hard parsing
• Resource efficiency
Compiling a program before every execution does not use resources efficiently, but
this is essentially what Oracle Database does when it performs a hard parse. The
database server must expend significant CPU and memory to create cursors,
generate and evaluate execution plans, and so on. By enabling the database to share
cursors, soft parsing consumes far fewer resources. If an application uses literals
instead of bind variables, but executes only a few queries each day, then DBAs may
not perceive the extra overhead as a performance problem. However, if an
application executes hundreds or thousands of queries per second, then the extra
• Scalability
When the database performs a hard parse, the database spends more time
acquiring and holding latches in the shared pool and library cache. Latches are
low-level serialization devices. The longer and more frequently the database
latches structures in shared memory, the longer the queue for these latches
becomes. When multiple statements share the same execution plan, the requests for
and durations of latches goes down, which increases scalability.
Video:
See RWP #4: Bind Variables and Soft Parsing for a demo showing the
performance benefits of bind variables
• Security
The only way to prevent SQL injection attacks is to use bind variables. Malicious
users can exploit application that concatenate strings by “injecting” code into the
application.
See Also:
• Your existing code has a serious security and scalability bug—the absence of bind
variables—and you need a temporary band-aid until the source code can be fixed.
• You set this initialization parameter at the session level and not at the instance
level.
Setting CURSOR_SHARING to FORCE has the following drawbacks:
• It indicates that the application does not use user-defined bind variables, which
means that it is open to SQL injection. Setting CURSOR_SHARING to FORCE does not
fix SQL injection bugs or render the code any more secure. The database binds
values only after any malicious SQL text has already been injected.
Video:
See RWP #4: Bind Variables and Soft Parsing for an AWR analysis by the Real-
World Performance group of an application that uses FORCE.
• The database must perform extra work during the soft parse to find a similar
statement in the shared pool.
• The database removes every literal, which means that it can remove useful
information. For example, the database strips out literal values in SUBSTR and
TO_DATE functions. The use of system-generated bind variables where literals are
more optimal can have a negative impact on execution plans.
See Also:
The Real-World Performance group recommends that you standardize spacing and
capitalization conventions for SQL statements and PL/SQL blocks. Also establish
conventions for the naming and definitions of bind variables. If the database does not
share cursors as expected, begin your diagnosis by querying V
$SQL_SHARED_CURSOR.
Example 15-15 Variations in SQL Text
In this example, an application that uses bind variables executes 7 statements using the
same bind variable value, but the statements are not textually identical:
7 rows selected.
The following query shows that the database did not share the cursor:
COL SQL_TEXT FORMAT a35
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
See Also:
Oracle Database Concepts for a brief conceptual overview of database
operations
Monitoring
Progress
• A frequently executed SQL statement is executing more slowly than normal. You
must identify the root cause of this problem.
• A parallel SQL statement is taking a long time. You want to determine how the
server processes are dividing the work.
• A periodic batch job containing many SQL statements must complete in a certain
number of hours, but took twice as long as expected.
• After a database upgrade, the execution time of an important batch job doubled. To
resolve this problem, you must collect enough relevant statistical data from the
batch job before and after the upgrade, compare the two sets of data, and then
identify the changes.
• Packing a SQL tuning set (STS) took far longer than anticipated (see “About SQL
Tuning Sets”). To diagnose the problem, you need to know what was being
executed over time. Because this issue cannot be easily reproduced, you need to
monitor the process while it is running.
DBMS_SQL_MONITOR
REPORT_SQL_MONITOR
Oracle
Enterprise
Manager
User
CONTROL_MANAGEMENT_PACK_ACCESS
As shown in Figure 16-1, you can use the DBMS_SQL_MONITOR package to define
database operations. After monitoring is initiated, the database stores metadata about
the database operations in AWR (see “Reporting on Database Operations Using SQL
Monitor”). The database refreshes monitoring statistics in close to real time as each
monitored statement executes, typically once every second. The database periodically
saves the data to disk.
Every monitored database operation has an entry in the V$SQL_MONITOR view. This
entry tracks key performance metrics collected for the execution, including the elapsed
time, CPU time, number of reads and writes, I/O wait time, and various other wait
times. The V$SQL_PLAN_MONITOR view includes monitoring statistics for each
operation in the execution plan of the SQL statement being monitored. You can access
reports by using DBMS_SQL_MONITOR.REPORT_SQL_MONITOR, which has an Oracle
Enterprise Manager Cloud Control (Cloud Control) interface.
See Also:
• An internally generated identifier to ensure that this primary key is truly unique
(SQL_EXEC_ID)
You can use zero or more additional attributes to describe and identify the
characteristics of a DB operation. Each attribute has a name and value. For example,
for operation daily_sales_report, you might define the attribute db_name and
assign it the value prod.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SQL_MONITOR.BEGIN_OPERATION function
• DBMS_SQL_MONITOR Package
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
DBMS_SQL_MONITOR Package
You can use the DBMS_SQL_MONITOR package to define the beginning and ending of a
database operation, and generate a report of the database operations.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SQL_MONITOR package
View Description
V$SQL_MONITOR This view contains global, high-level information about the
top SQL statements in a database operation.
Each monitored SQL statement has an entry in this view.
Each row contains a SQL statement whose statistics are
accumulated from multiple sessions and all of its executions
in the operation. The primary key is the combination of the
columns DBOP_NAME, DBOP_EXEC_ID, and SQL_ID.
The V$SQL_MONITOR view contains a subset of the statistics
available in V$SQL. However, unlike V$SQL, monitoring
statistics are not cumulative over several executions. Instead,
one entry in V$SQL_MONITOR is dedicated to a single
execution of a SQL statement. If the database monitors two
executions of the same SQL statement, then each execution
has a separate entry in V$SQL_MONITOR.
V$SQL_MONITOR has one entry for the parallel execution
coordinator process, and one entry for each parallel execution
server process. Each entry has corresponding entries in V
$SQL_PLAN_MONITOR. Because the processes allocated for
the parallel execution of a SQL statement are cooperating for
the same execution, these entries share the same execution
key (the composite SQL_ID, SQL_EXEC_START and
SQL_EXEC_ID). You can aggregate the execution key to
determine the overall statistics for a parallel execution.
V$SQL_MONITOR_SESSTAT This view contains the statistics for all sessions involved in
the database operation.
Most of the statistics are cumulative. The database stores the
statistics in XML format instead of using each column for
each statistic. This view is primarily intended for the report
generator. Oracle recommends that you use V$SESSTAT
instead of V$SQL_MONITOR_SESSTAT.
View Description
V$SQL_PLAN_MONITOR This view contains monitoring statistics for each step in the
execution plan of the monitored SQL statement.
The database updates statistics in V$SQL_PLAN_MONITOR
every second while the SQL statement is executing. Multiple
entries exist in V$SQL_PLAN_MONITOR for every monitored
SQL statement. Each entry corresponds to a step in the
execution plan of the statement.
You can use the preceding views with the following views to get additional
information about the monitored execution:
• V$ACTIVE_SESSION_HISTORY
• V$SESSION
• V$SESSION_LONGOPS
• V$SQL
• V$SQL_PLAN
See Also:
Oracle Database Reference to learn about the V$ views for database operations
monitoring
Prerequisites
Because SQL monitoring is a feature of the Oracle Database Tuning Pack, the
CONTROL_MANAGEMENT_PACK_ACCESS initialization parameter must be set to
DIAGNOSTIC+TUNING (the default value).
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the current database operations settings.
For example, run the following SQL*Plus command:
SQL> SHOW PARAMETER statistics_level
See Also:
Assumptions
This tutorial assumes the following:
• You want to disable automatic monitoring for the statement SELECT * FROM
sales ORDER BY time_id.
See Also:
Oracle Database SQL Language Reference for information about using the
MONITOR and NO_MONITOR hints
Assumptions
This tutorial assumes the following:
• You are an administrator and want to query the number of items in the sh.sales
table and the number of customers in the sh.customers table.
COUNT(*)
----------
918843
COUNT(*)
----------
55500
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SQL_MONITOR package
• GV$SQL_MONITOR
• GV$SQL_PLAN_MONITOR
• GV$SQL_MONITOR_SESSTAT
• GV$SQL
• GV$SQL_PLAN
• GV$ACTIVE_SESSION_HISTORY
• GV$SESSION_LONGOPS
• DBA_HIST_REPORTS
• DBA_HIST_REPORTS_DETAILS
Assumptions
This tutorial assumes the following:
• The user sh is executing the following long-running parallel query of the sales
made to each customer:
SELECT c.cust_id, c.cust_last_name, c.cust_first_name,
s.prod_id, p.prod_name, s.time_id
FROM sales s, customers c, products p
WHERE s.cust_id = c.cust_id
AND s.prod_id = p.prod_id
ORDER BY c.cust_id, s.time_id;
• You want to ensure that the preceding query does not consume excessive
resources. While the statement executes, you want to determine basic statistics
about the database operation, such as the level of parallelism, the total database
time, and number of I/O requests.
Note:
To generate the SQL monitor report from the command line, run the
REPORT_SQL_MONITOR function in the DBMS_SQLTUNE package, as in the
following sample SQL*Plus script:
VARIABLE my_rept CLOB
BEGIN
:my_rept :=DBMS_SQLTUNE.REPORT_SQL_MONITOR();
END;
/
PRINT :my_rept
In this example, the query has been executing for 1.4 minutes.
2. Click the value in the SQL ID column to see details about the statement.
The Monitored SQL Details page appears.
The preceding report shows the execution plan and statistics relating to statement
execution. For example, the Timeline column shows when each step of the
execution plan was active. Times are shown relative to the beginning and end of
the statement execution. The Executions column shows how many times an
operation was executed.
3. In the Overview section, click the link next to the SQL text.
A message shows the full text of the SQL statement.
4. In the Time & Wait Statistics section, next to Database Time, move the cursor over
the largest portion on the bar graph.
A message shows that user I/O is consuming over half of database time.
Database Time measures the amount of time the database has spent working on
this SQL statement. This value includes CPU and wait times, such as I/O time.
The bar graph is divided into several color-coded portions to highlight CPU
resources, user I/O resources, and other resources. You can move the cursor over
any portion to view the percentage value of the total.
5. In the Details section, in the IO Requests column, move the cursor over the I/O
requests bar to view the percentage value of the total.
A message appears.
In the preceding graphic, the IO Requests message shows the total number of read
requests issued by the monitored SQL. The message shows that read requests
form 80% of the total I/O requests.
See Also:
• Oracle Database Reference to learn about the V$ and data dictionary views
for database operations monitoring
A SQL test case is a set of information that enables a developer to reproduce the
execution plan for a specific SQL statement that has encountered a performance
problem. SQL Test Case Builder is a tool that automatically gathers information
needed to reproduce the problem in a different database instance.
This chapter contains the following topics:
• SQL Incidents
SQL Incidents
In the fault diagnosability infrastructure of Oracle Database, an incident is a single
occurrence of a problem. A SQL incident is a SQL-related problem. When a problem
(critical error) occurs multiple times, the database creates an incident for each
occurrence. Incidents are timestamped and tracked in the Automatic Diagnostic
Repository (ADR). Each incident is identified by a numeric incident ID, which is
unique within the ADR.
SQL Test Case Builder is accessible any time on the command line. In Oracle
Enterprise Manager Cloud Control (Cloud Control), the SQL Test Case pages are only
available after a SQL incident is found.
See Also:
• Adaptive plans
SQL Test Case Builder captures inputs to the decisions made regarding adaptive
plans, and replays them at each decision point (see “Adaptive Plans”). For adaptive
plans, the final statistics value at each buffering statistics collector is sufficient to
decide on the final plan.
• Dynamic statistics
Regathering dynamic statistics on a different database does not always generate the
same results, for example, when data is missing (see “Dynamic Statistics”). To
reproduce the problem, SQL Test Case Builder exports the dynamic statistics result
from the source database. In the testing database, SQL Test Case Builder reuses the
same values captured from the source database instead of regathering dynamic
statistics.
nondefault parameter values are used, SQL Test Case Builder re-establishes the
same values before running the query.
• Statement history
The statement history is important for diagnosing problems related to adaptive
cursor sharing, statistics feedback, and cursor sharing bugs. The history includes
execution plans and compilation and execution statistics.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_STATS package
You can specify a nondefault location by creating an Oracle directory and invoking
DBMS_SQLDIAG.EXPORT_SQL_TESTCASE, as in the following example:
CREATE OR REPLACE DIRECTORY my_tcb_dir_exp '/tmp';
BEGIN
DBMS_SQLDIAG.EXPORT_SQL_TESTCASE (
directory => 'my_tcb_dir_exp'
, sql_text => 'SELECT COUNT(*) FROM sales'
, testcase => tco
);
END;
See Also:
Oracle Database Administrator's Guide to learn about the structure of the ADR
repository
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
2. In the Incidents and Problems section, locate the SQL incident to be investigated.
In the following example, the ORA 600 error is a SQL incident.
The Support Workbench page appears, with the incidents listed in a table.
See Also:
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
2. From the Oracle Database menu, select Diagnostics, then Support Workbench.
The Support Workbench page appears, with the incidents listed in a table.
See Also:
Procedure Description
EXPORT_SQL_TESTCASE Exports a SQL test case to a user-specified
directory
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about the
DBMS_SQLDIAG package
Assumptions
This tutorial assumes the following:
• You ran the following EXPLAIN PLAN statement as user sh, which causes an
internal error:
EXPLAIN PLAN FOR
SELECT unit_cost, sold
FROM costs c,
( SELECT /*+ merge */ p.prod_id, SUM(quantity_sold) AS sold
FROM products p, sales s
WHERE p.prod_id = s.prod_id
GROUP BY p.prod_id ) v
WHERE c.prod_id = v.prod_id;
• In the Incidents and Problems section on the Database Home page, a SQL incident
generated by the internal error appears.
8. Access the SQL Test Case files in the location described in “Output of SQL Test
Case Builder”.
See Also:
See Also:
SQL*Plus User's Guide and Reference for information about the use of Autotrace
to trace and tune SQL*Plus statements
• Client identifier - specifies an end user based on the logon ID, such as HR.HR
See Also:
Oracle Database PL/SQL Packages and Types Reference for information about the
DBMS_MONITOR, DBMS_SESSION, DBMS_SERVICE, and
DBMS_APPLICATION_INFO packages
• Wait event data for each SQL statement, and a summary for each trace file
If the cursor for the SQL statement is closed, then SQL Trace also provides row source
information that includes:
• Row operations showing the actual execution plan of each SQL statement
See Also:
Overview of TKPROF
You can run the TKPROF program to format the contents of the trace file and place the
output into a readable output file. TKPROF can also:
Note:
If the cursor for a SQL statement is not closed, then TKPROF output does not
automatically include the actual execution plan of the SQL statement. In this
situation, use the EXPLAIN option with TKPROF to generate an execution
plan.
TKPROF reports each statement executed with the resources it has consumed, the
number of times it was called, and the number of rows which it processed. This
information enables you to locate those statements that are using the greatest resource.
With baselines available, you can assess whether the resources used are reasonable
given the work done.
Assumptions
This tutorial assumes that you want to enable and then disable statistics gathering for
the client with the ID oe.oe.
1. Start SQL*Plus, and then connect to the database with the appropriate privileges.
Assumptions
This tutorial assumes that you want to gather statistics as follows:
To enable and disable statistics gathering for a service, module, and action:
1. Start SQL*Plus, and then connect to the database with the appropriate privileges.
2. Enable statistics gathering for the desired service, module, and action.
BEGIN
DBMS_MONITOR.SERV_MOD_ACT_STAT_ENABLE(
service_name => 'ACCTG' ,
module_name => 'GLEDGER' ,
action_name => 'INSERT ITEM' );
END;
Assumptions
This tutorial assumes the following:
1. Start SQL*Plus, and then connect to the database with the appropriate privileges.
Assumptions
This tutorial assumes the following:
• You want to enable tracing for all actions for the combination of the ACCTG service
and the PAYROLL module.
1. Start SQL*Plus, and then connect to the database with the appropriate privileges.
Assumptions
This tutorial assumes the following:
1. Start SQL*Plus, and then connect to the database with the administrator
privileges.
2. Determine the session ID and serial number values for the session to trace.
For example, query V$SESSION as follows:
SELECT SID, SERIAL#, USERNAME
FROM V$SESSION
WHERE USERNAME = 'OE';
3. Use the values from the preceding step to enable tracing for a specific session.
For example, execute the following program to enable tracing for the OE session,
where the true argument includes wait information in the trace and the false
argument excludes bind information from the trace:
BEGIN
DBMS_MONITOR.SESSION_TRACE_ENABLE(
session_id => 27 ,
serial_num => 60 ,
waits => true ,
Prerequisites
You must be logged in as an administrator execute the DATABASE_TRACE_ENABLE
procedure.
Assumptions
This tutorial assumes the following:
• You want to enable tracing for all SQL the inst1 instance.
1. Start SQL*Plus, and then connect to the database with the administrator
privileges.
To disable the session-level SQL tracing for an entire database, invoke the
DATABASE_TRACE_DISABLE procedure without specifying the instance_name
parameter:
EXECUTE DBMS_MONITOR.DATABASE_TRACE_DISABLE();
2. Enable the SQL Trace facility for the desired session, and run the application. This
step produces a trace file containing statistics for the SQL statements issued by the
application.
See “Step 2: Enabling the SQL Trace Facility”.
3. Run TKPROF to translate the trace file created in Step 2 into a readable output file.
This step can optionally create a SQL script that you can use to store the statistics
in a database.
See “Step 3: Generating Output Files with TKPROF”.
4. Optionally, run the SQL script produced in Step 3 to store the statistics in the
database.
See “Step 4: Storing SQL Trace Facility Statistics”.
Parameter Description
Parameter Description
3. If the operating system retains multiple versions of files, then ensure that the
version limit is high enough to accommodate the number of trace files you expect
the SQL Trace facility to generate.
4. If the generated trace files can be owned by an operating system user other than
yourself, then ensure that you have the necessary permissions to use TKPROF to
format them.
• Database instance
• Database session
Use DBMS_SESSION.SET_SQL_TRACE procedure to enable tracing (true) or
disable tracing (false).
Note:
Because running the SQL Trace facility increases system overhead, enable it
only when tuning SQL statements, and disable it when you are finished.
1. Start SQL*Plus, and connect to the database with the desired credentials.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about
DBMS_MONITOR.DATABASE_TRACE_ENABLE
After the SQL Trace facility has generated trace files, you can:
• Run TKPROF on each individual trace file, producing several formatted output
files, one for each session.
• Concatenate the trace files, and then run TKPROF on the result to produce a
formatted output file for the entire instance.
Note:
The following SQL statements are truncated to 25 characters in the SQL Trace
file:
SET ROLE
GRANT
ALTER USER
ALTER ROLE
CREATE USER
CREATE ROLE
14 MERGE JOIN
4 SORT JOIN
4 TABLE ACCESS (FULL) OF 'DEPT'
14 SORT JOIN
14 TABLE ACCESS (FULL) OF 'EMP'
• The number of library cache misses for the parsing and execution of the statement.
• INSERT statements that add rows of statistics, one for each traced SQL statement,
to TKPROF_TABLE.
After running TKPROF, run this script to store the statistics in the database.
DATE_OF_INSERT DATE,
CURSOR_NUM NUMBER,
DEPTH NUMBER,
USER_ID NUMBER,
PARSE_CNT NUMBER,
PARSE_CPU NUMBER,
PARSE_ELAP NUMBER,
PARSE_DISK NUMBER,
PARSE_QUERY NUMBER,
PARSE_CURRENT NUMBER,
PARSE_MISS NUMBER,
EXE_COUNT NUMBER,
EXE_CPU NUMBER,
EXE_ELAP NUMBER,
EXE_DISK NUMBER,
EXE_QUERY NUMBER,
EXE_CURRENT NUMBER,
EXE_MISS NUMBER,
EXE_ROWS NUMBER,
FETCH_COUNT NUMBER,
FETCH_CPU NUMBER,
FETCH_ELAP NUMBER,
FETCH_DISK NUMBER,
FETCH_QUERY NUMBER,
FETCH_CURRENT NUMBER,
FETCH_ROWS NUMBER,
CLOCK_TICKS NUMBER,
SQL_STATEMENT LONG);
Most output table columns correspond directly to the statistics that appear in the
formatted output file. For example, the PARSE_CNT column value corresponds to the
count statistic for the parse step in the output file.
The columns in Table 18-2 help you identify a row of statistics.
Column Description
SQL_STATEMENT This is the SQL statement for which the SQL Trace facility collected
the row of statistics. Because this column has data type LONG, you
cannot use it in expressions or WHERE clause conditions.
DATE_OF_INSERT This is the date and time when the row was inserted into the table.
This value is different from the time when the SQL Trace facility
collected the statistics.
DEPTH This indicates the level of recursion at which the SQL statement was
issued. For example, a value of 0 indicates that a user issued the
statement. A value of 1 indicates that Oracle Database generated the
statement as a recursive call to process a statement with a value of 0
(a statement issued by a user). A value of n indicates that Oracle
Database generated the statement as a recursive call to process a
statement with a value of n-1.
USER_ID This identifies the user issuing the statement. This value also
appears in the formatted output file.
CURSOR_NUM Oracle Database uses this column value to keep track of the cursor to
which each SQL statement was assigned.
The output table does not store the statement's execution plan. The following query
returns the statistics from the output table. These statistics correspond to the formatted
output shown in “Example 18-7”.
SELECT * FROM TKPROF_TABLE;
SQL_STATEMENT
---------------------------------------------------------------------
SELECT * FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO
Note:
Recursive SQL statistics are not included for SQL-level operations.
If it is acceptable to have 7.01 CPU seconds and to retrieve 824 rows, then you need
not look any further at this trace output. In fact, a major use of TKPROF reports in a
tuning exercise is to eliminate processes from the detailed tuning phase.
The output indicates that 10 unnecessary parse call were made (because 11 parse calls
exist for this single statement) and that array fetch operations were performed. More
rows were fetched than there were fetches performed. A large gap between CPU and
elapsed timings indicates Physical I/Os.
See Also:
Example 18-4
0 SELECT STATEMENT
2340 TABLE ACCESS (BY ROWID) OF 'CQ_NAMES'
0 INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON-UNIQUE)
Two statistics suggest that the query might have been executed with a full table scan.
These statistics are the current mode block visits, plus the number of rows originating
from the Table Access row source in the execution plan. The explanation is that the
required index was built after the trace file had been produced, but before TKPROF
had been run.
Generating a new trace file gives the following data:
SELECT name_id
FROM cq_names
WHERE name = 'FLOOR';
One of the marked features of this correct version is that the parse call took 10
milliseconds of CPU time and 20 milliseconds of elapsed time, but the query
apparently took no time at all to execute and perform the fetch. These anomalies arise
because the clock tick of 10 milliseconds is too long relative to the time taken to
execute and fetch the data. In such cases, it is important to get lots of executions of the
statements, so that you have statistically valid numbers.
Again, the answer is interference from another transaction. In this case, another
transaction held a shared lock on the table cq_names for several seconds before and
after the update was issued. It takes a fair amount of experience to diagnose that
interference effects are occurring. On the one hand, comparative data is essential when
the interference is contributing only a short delay (or a small increase in block visits in
the previous example). However, if the interference contributes only modest overhead,
and if the statement is essentially efficient, then its statistics may not require analysis.
• TRCSESS
• TKPROF
TRCSESS
The TRCSESS utility consolidates trace output from selected trace files based on user-
specified criteria. After TRCSESS merges the trace information into a single output file,
TKPROF can process the output file.
Purpose
TRCSESS is useful for consolidating the tracing of a particular session for performance
or debugging purposes.
Tracing a specific session is usually not a problem in the dedicated server model
because one process serves a session during its lifetime. You can see the trace
information for the session from the trace file belonging to the server process.
However, in a shared server configuration, a user session is serviced by different
processes over time. The trace for the user session is scattered across different trace
files belonging to different processes, which makes it difficult to get a complete picture
of the life cycle of a session.
Guidelines
You must specify one of the session, clientid, service, action, or module
options. If you specify multiple options, then TRCSESS consolidates all trace files that
satisfy the specified criteria into the output file.
Syntax
trcsess [output=output_file_name]
[session=session_id]
[clientid=client_id]
[service=service_name]
[action=action_name]
[module=module_name]
[trace_files]
Options
Argument Description
output Specifies the file where the output is generated. If this option is not
specified, then the utility writes to standard output.
Argument Description
session Consolidates the trace information for the session specified. The
session identifier is a combination of session index and session serial
number, such as 21.2371. You can locate these values in the V
$SESSION view.
clientid Consolidates the trace information for the specified client ID.
service Consolidates the trace information for the specified service name.
action Consolidates the trace information for the specified action name.
module Consolidates the trace information for the specified module name.
trace_files Lists the trace file names, separated by spaces, in which TRCSESS
should look for trace information. You can use the wildcard character
(*) to specify the trace file names. If you do not specify trace files, then
TRCSESS uses all files in the current directory as input.
Examples
Example 18-2 Tracing a Single Session
This sample output of TRCSESS shows the container of traces for a particular session.
In this example, the session index and serial number equals 21.2371. All files in
current directory are taken as input.
trcsess session=21.2371
TKPROF
The TKPROF program formats the contents of the trace file and places the output into
a readable output file. TKPROF can also:
Note:
If the cursor for a SQL statement is not closed, then TKPROF output does not
automatically include the actual execution plan of the SQL statement. In this
situation, use the EXPLAIN option with TKPROF to generate an execution
plan.
TKPROF reports each statement executed with the resources it has consumed, the
number of times it was called, and the number of rows which it processed.
Purpose
TKPROF can locate statements using the greatest resource. With baselines available,
you can assess whether the resources used are reasonable given the work done.
Guidelines
The input and output files are the only required arguments. If you invoke TKPROF
without arguments, then the tool displays online help.
Syntax
tkprof input_file output_file
[ waits=yes|no ]
[ sort=option ]
[ print=n ]
[ aggregate=yes|no ]
[ insert=filename3 ]
[ sys=yes|no ]
[ table=schema.table ]
[ explain=user/password ]
[ record=filename4 ]
[ width=n ]
Options
Argument Description
input_file Specifies the input file, a trace file containing statistics produced by the
SQL Trace facility. This file can be either a trace file produced for a single
session, or a file produced by concatenating individual trace files from
multiple sessions.
output_file Specifies the file to which TKPROF writes its formatted output.
Argument Description
WAITS Specifies whether to record summary for any wait events found in the
trace file. Valid values are YES (default) and NO.
SORT Sorts traced SQL statements in descending order of specified sort option
before listing them in the output file. If multiple options are specified,
then the output is sorted in descending order by the sum of the values
specified in the sort options. If you omit this parameter, then TKPROF
lists statements into the output file in order of first use. Sort options are
listed as follows:
• PRSCNT - Number of times parsed
• PRSCPU - CPU time spent parsing
• PRSELA - Elapsed time spent parsing
• PRSDSK - Number of physical reads from disk during parse
• PRSQRY - Number of consistent mode block reads during parse
• PRSCU - Number of current mode block reads during parse
• PRSMIS - Number of library cache misses during parse
• EXECNT - Number of executions
• EXECPU - CPU time spent executing
• EXEELA - Elapsed time spent executing
• EXEDSK - Number of physical reads from disk during execute
• EXEQRY - Number of consistent mode block reads during execute
• EXECU - Number of current mode block reads during execute
• EXEROW - Number of rows processed during execute
• EXEMIS - Number of library cache misses during execute
• FCHCNT - Number of fetches
• FCHCPU - CPU time spent fetching
• FCHELA - Elapsed time spent fetching
• FCHDSK - Number of physical reads from disk during fetch
• FCHQRY - Number of consistent mode block reads during fetch
• FCHCU - Number of current mode block reads during fetch
• FCHROW - Number of rows fetched
• USERID - Userid of user that parsed the cursor
PRINT Lists only the first integer sorted SQL statements from the output file. If
you omit this parameter, then TKPROF lists all traced SQL statements.
This parameter does not affect the optional SQL script. The SQL script
always generates insert data for all traced SQL statements.
AGGREGATE If you specify AGGREGATE = NO, then TKPROF does not aggregate
multiple users of the same SQL text.
INSERT Creates a SQL script that stores the trace file statistics in the database.
TKPROF creates this script with the name filename3. This script creates
a table and inserts a row of statistics for each traced SQL statement into
the table.
SYS Enables and disables the listing of SQL statements issued by the user
SYS, or recursive SQL statements, into the output file. The default value
of YES causes TKPROF to list these statements. The value of NO causes
TKPROF to omit them. This parameter does not affect the optional SQL
script. The SQL script always inserts statistics for all traced SQL
statements, including recursive SQL statements.
Argument Description
TABLE Specifies the schema and name of the table into which TKPROF
temporarily places execution plans before writing them to the output file.
If the specified table exists, then TKPROF deletes all rows in the table,
uses it for the EXPLAIN PLAN statement (which writes more rows into
the table), and then deletes those rows. If this table does not exist, then
TKPROF creates it, uses it, and then drops it.
The specified user must be able to issue INSERT, SELECT, and DELETE
statements against the table. If the table does not exist, then the user must
also be able to issue CREATE TABLE and DROP TABLE statements. For the
privileges to issue these statements, see Oracle Database SQL Language
Reference.
This option enables multiple individuals to run TKPROF concurrently
with the same user in the EXPLAIN value. These individuals can specify
different TABLE values and avoid destructively interfering with each
other's processing on the temporary plan table.
TKPROF supports the following combinations:
• The EXPLAIN parameter without the TABLE parameter
TKPROF uses the table PROF$PLAN_TABLE in the schema of the user
specified by the EXPLAIN parameter
• The TABLE parameter without the EXPLAIN parameter
TKPROF ignores the TABLE parameter.
If no plan table exists, then TKPROF creates the table PROF$PLAN_TABLE
and then drops it at the end.
EXPLAIN Determines the execution plan for each SQL statement in the trace file
and writes these execution plans to the output file. TKPROF also displays
the number of rows processed by each step of the execution plan.
TKPROF determines execution plans by issuing the EXPLAIN PLAN
statement after connecting to Oracle Database with the user and
password specified in this parameter. The specified user must have
CREATE SESSION system privileges. TKPROF takes longer to process a
large trace file if the EXPLAIN option is used.
Note: Trace files generated immediately after instance startup contain
data that reflects the activity of the startup process. In particular, they
reflect a disproportionate amount of I/O activity as caches in the system
global area (SGA) are filled. For the purposes of tuning, ignore such trace
files.
RECORD Creates a SQL script with the specified filename with all of the
nonrecursive SQL in the trace file. You can use this script to replay the
user events from the trace file.
WIDTH An integer that controls the output line width of some TKPROF output,
such as the explain plan. This parameter is useful for post-processing of
TKPROF output.
Output
This section explains the TKPROF output.
multiple users, then TKPROF lists the ID of the last user to parse the statement. The
user ID of all database users appears in the data dictionary in the column
ALL_USERS.USER_ID.
FETCH Retrieves rows returned by a query. Fetches are only performed for
SELECT statements.
The other columns of the SQL Trace facility output are combined statistics for all
parses, executions, and fetches of a statement. The sum of query and current is the
total number of buffers accessed, also called Logical I/Os (LIOs). See Table 18-5.
Table 18-5 SQL Trace Statistics for Parses, Executes, and Fetches.
CPU Total CPU time in seconds for all parse, execute, or fetch calls for the
statement. This value is zero (0) if TIMED_STATISTICS is not
enabled.
ELAPSED Total elapsed time in seconds for all parse, execute, or fetch calls for
the statement. This value is zero (0) if TIMED_STATISTICS is not
enabled.
DISK Total number of data blocks physically read from the data files on
disk for all parse, execute, or fetch calls.
QUERY Total number of buffers retrieved in consistent mode for all parse,
execute, or fetch calls. Usually, buffers are retrieved in consistent
mode for queries.
Statistics about the processed rows appear in the ROWS column. The column shows the
number of rows processed by the SQL statement. This total does not include rows
processed by subqueries of the SQL statement. For SELECT statements, the number of
rows returned appears for the fetch step. For UPDATE, DELETE, and INSERT
statements, the number of rows processed appears for the execute step.
Note:
The row source counts are displayed when a cursor is closed. In SQL*Plus,
there is only one user cursor, so each statement executed causes the previous
cursor to be closed; therefore, the row source counts are displayed. PL/SQL
has its own cursor handling and does not close child cursors when the parent
cursor is closed. Exiting (or reconnecting) causes the counts to be displayed.
In the following sample TKPROF output, note the cr, r, w, and time values under the
Row Source Operation column:
Rows Row Source Operation
------- ---------------------------------------------------
0 DELETE (cr=43141 r=266947 w=25854 time=60235565 us)
28144 HASH JOIN ANTI (cr=43057 r=262332 w=25854 time=48830056 us)
51427 TABLE ACCESS FULL STATS$SQLTEXT (cr=3465 r=3463 w=0 time=865083 us)
647529 INDEX FAST FULL SCAN STATS$SQL_SUMMARY_PK
(cr=39592 r=39325 w=0 time=10522877 us) (object id 7409)
In addition, wait events are summed for the entire trace file at the end of the file.
To ensure that wait events information is written to the trace file for the session, run
the following SQL statement:
ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';
Examples
Example 18-4 Printing the Most Resource-Intensive Statements
If you are processing a large trace file using a combination of SORT parameters and the
PRINT parameter, then you can produce a TKPROF output file containing only the
highest resource-intensive statements. The following statement prints the 10
statements in the trace file that have generated the most physical I/O:
TKPROF ora53269.trc ora53269.prf SORT = (PRSDSK, EXEDSK, FCHDSK) PRINT = 10
This example is likely to be longer than a single line on the screen, and you might need
to use continuation characters, depending on the operating system.
Note the other parameters in this example:
• The EXPLAIN value causes TKPROF to connect as the user hr and use the EXPLAIN
PLAN statement to generate the execution plan for each traced SQL statement. You
can use this to get access paths and row source counts.
Note:
If the cursor for a SQL statement is not closed, then TKPROF output does not
automatically include the actual execution plan of the SQL statement. In this
situation, you can use the EXPLAIN option with TKPROF to generate an
execution plan.
• The TABLE value causes TKPROF to use the table temp_plan_table_a in the
schema scott as a temporary plan table.
• The INSERT value causes TKPROF to generate a SQL script named STOREA.SQL
that stores statistics for all traced SQL statements in the database.
• The SYS parameter with the value of NO causes TKPROF to omit recursive SQL
statements from the output file. In this way, you can ignore internal Oracle
Database statements such as temporary table operations.
• The SORT value causes TKPROF to sort the SQL statements in order of the sum of
the CPU time spent executing and the CPU time spent fetching rows before writing
them to the output file. For greatest efficiency, always use SORT parameters.
Example 18-6 TKPROF Header
This example shows a sample header for the TKPROF report.
TKPROF: Release 12.1.0.0.2
Copyright (c) 1982, 2012, Oracle and/or its affiliates. All rights reserved.
********************************************************************************
count = number of times OCI procedure was executed
cpu = cpu time in seconds executing
elapsed = elapsed time in seconds executing
disk = number of physical reads of buffers from disk
query = number of buffers gotten for consistent read
current = number of buffers gotten in current mode (usually for update)
rows = number of rows processed by the fetch or execute call
********************************************************************************
select condition
from
cdef$ where rowid=:1
********************************************************************************
********************************************************************************
delete
from stats$sqltext st
where (hash_value, text_subset) not in
(select --+ hash_aj
hash_value, text_subset
from stats$sql_summary ss
where ( ( snap_id < :lo_snap
or snap_id > :hi_snap
)
and dbid = :dbid
and instance_number = :inst_num
)
or ( dbid != :dbid
or instance_number != :inst_num)
)
• Associated execution context, such as user schema, application module name and
action, list of bind values, and the environment for SQL compilation of the cursor
• Associated basic execution statistics, such as elapsed time, CPU time, buffer gets,
disk reads, rows processed, cursor fetches, the number of executions, the number of
complete executions, optimizer cost, and the command type
• Associated execution plans and row source statistics for each SQL statement
(optional)
The database stores SQL tuning sets in a database-provided schema.
This section contains the following topics:
Note:
Data visibility and privilege requirements may differ when using an STS with
pluggable databases. See Oracle Database Administrator's Guide for a table that
summarizes how manageability features work in a container database (CDB).
Custom
SQL
SQL Access
Advisor
AWR
Shared SQL
Area Filter
STS
Transport
• Filter SQL statements using the application module name and action, or any
execution statistics
See Also:
Oracle Database Performance Tuning Guide to learn about AWR
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
2. From the Performance menu, select SQL, then SQL Tuning Sets.
The SQL Tuning Sets page appears, as shown in Figure 19-2.
See Also:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about
DBMS_SQLTUNE
Populate STS
LOAD_SQLSET with SQL
CREATE_STGTAB_SQLSET
Optionally, transport
PACK_STGTAB_SQLSET STS to different
database
Transport STS
UNPACK_STGTAB_SQLSET
Drop STS
DROP_SQLSET
Parameter Description
Assumptions
This tutorial assumes that you want to create an STS named SQLT_WKLD_STS.
To create an STS:
1. Connect SQL*Plus to the database with the appropriate privileges, and then run
the DBMS_SQLTUNE.CREATE_SQLSET procedure.
For example, execute the following PL/SQL program:
BEGIN
DBMS_SQLTUNE.CREATE_SQLSET (
sqlset_name => 'SQLT_WKLD_STS'
, description => 'STS to store SQL from the private SQL area'
);
END;
shared SQL area. For both the workload repository and SQL tuning sets, predefined
table functions can select columns from the source to populate a new STS.
Table 19-2 describes some DBMS_SQLTUNE.LOAD_SQLSET procedure parameters. See
Oracle Database PL/SQL Packages and Types Reference for complete reference
information.
Parameter Description
populate_cursor Specifies the cursor reference from which to populate the STS.
load_option Specifies how the statements are loaded into the STS. The
possible values are INSERT (default), UPDATE, and MERGE.
Prerequisites
This tutorial has the following prerequisites:
• The current user must have privileges on the shared SQL area views.
Assumptions
This tutorial assumes that you want to load the SQL tuning set named
SQLT_WKLD_STS with statements from the shared SQL area.
To load an STS:
Parameter Description
basic_filter The SQL predicate to filter the SQL from the STS defined on
attributes of the SQLSET_ROW
object_filter Specifies the objects that exist in the object list of selected SQL from
the shared SQL area
Table 19-4 describes some attributes of the SQLSET_ROW object. These attributes
appears as columns when you query TABLE(DBMS_SQLTUNE.SELECT_SQLSET()).
Parameter Description
elapsed_time Sum of the total number of seconds elapsed for this SQL
statement
Assumptions
This tutorial assumes that you want to display the contents of an STS named
SQLT_WKLD_STS.
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the STS contents using the TABLE function.
Assumptions
This tutorial assumes that you want to modify SQLT_WKLD_STS as follows:
• You want to delete all SQL statements with fetch counts over 100.
• You want to change the priority of the SQL statement with ID fudq5z56g642p to
1. You can use priority as a ranking criteria when running SQL Tuning Advisor.
1. Connect SQL*Plus to the database with the appropriate privileges, and then
optionally query the STS contents using the TABLE function.
For example, execute the following query:
SELECT SQL_ID, ELAPSED_TIME, FETCHES, EXECUTIONS
FROM TABLE(DBMS_SQLTUNE.SELECT_SQLSET('SQLT_WKLD_STS'));
4. Optionally, query the STS to confirm that the intended modifications were made.
For example, execute the following query:
SELECT SQL_ID, ELAPSED_TIME, FETCHES, EXECUTIONS, PRIORITY
FROM TABLE(DBMS_SQLTUNE.SELECT_SQLSET('SQLT_WKLD_STS'));
Production Test
Database Database
1. In the production database, pack the STS into a staging table using
DBMS_SQLTUNE.PACK_STGTAB_SQLSET.
2. Export the STS from the staging table to a .dmp file using Oracle Data Pump.
3. Transfer the .dmp file from the production host to the test host using a transfer
tool such as ftp.
4. In the test database, import the STS from the .dmp file to a staging table using
Oracle Data Pump.
Basic Steps for Transporting SQL Tuning Sets from a Non-CDB to a CDB
When you transport an STS from a non-CDB to a CDB database, you must remap the
con_dbid of each SQL statement in the STS to a con_dbid within the destination
CDB. The basic steps are as follows:
See Also:
Procedure Description
Table 19-5 (Cont.) DBMS_SQLTUNE Procedures for Transporting SQL Tuning Sets
Procedure Description
UNPACK_STGTAB_SQLSET Copy the SQL tuning sets from the staging table into a
database
Assumptions
This tutorial assumes the following:
• An STS with regressed SQL resides in a production database created in the current
release.
• You run SQL Performance Analyzer trials on a remote test database created in
Oracle Database 11g Release 2 (11.2).
• You want to copy the STS from the production database to the test database and
tune the regressions from the SQL Performance Analyzer trials.
• You want to use Oracle Database Pump to transfer the SQL tuning sets between
database hosts.
To transport an STS:
3. Use the PACK_STGTAB_SQLSET procedure to populate the staging table with SQL
tuning sets.
The following example populates dba1.my_11g_staging_table with the STS
my_sts owned by hr:
BEGIN
DBMS_SQLTUNE.PACK_STGTAB_SQLSET (
sqlset_name => 'sqlt_wkld_sts'
, sqlset_owner => 'sh'
, staging_table_name => 'my_11g_staging_table'
, staging_schema_owner => 'dba1'
, db_version => DBMS_SQLTUNE.STS_STGTAB_11_2_VERSION
);
END;
/
4. Use Oracle Data Pump to export the contents of the statistics table.
For example, run the expdp command at the operating system prompt:
expdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=sts.dmp TABLES=my_11g_staging_table
6. Log in to the test host as an administrator, and then use Oracle Data Pump to
import the contents of the statistics table.
For example, run the impdp command at the operating system prompt:
impdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=sts.dmp TABLES=my_11g_staging_table
Prerequisites
Ensure that no tuning task is currently using the STS to be dropped. If a tuning task
exists that is using this STS, then drop the task before dropping the STS. Otherwise,
the database issues an ORA-13757 error.
Assumptions
This tutorial assumes that you want to drop an STS named SQLT_WKLD_STS.
To drop an STS:
1. Connect SQL*Plus to the database with the appropriate privileges, and then run
the DBMS_SQLTUNE.DROP_SQLSET procedure.
For example, execute the following PL/SQL program:
BEGIN
DBMS_SQLTUNE.DROP_SQLSET( sqlset_name => 'SQLT_WKLD_STS' );
END;
/
SELECT COUNT(*)
FROM USER_SQLSET
WHERE NAME = 'SQLT_WKLD_STS';
COUNT(*)
----------
0
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the STS
procedures in DBMS_SQLTUNE
This chapter explains the concepts and tasks relating to SQL Tuning Advisor.
This chapter contains the following topics:
• Creation of indexes
Identifying and tuning high-load SQL statements is challenging even for an expert.
SQL Tuning Advisor uses the optimizer to tune SQL for you.
• Enable developers to tune SQL on a test system instead of the production system
When suboptimally performing SQL statements occur on a production database,
developers may not want to investigate and tune directly on the production
database. The DBA can transport the problematic SQL statements to a test database
where the developers can safely analyze and tune them.
When tuning multiple statements, SQL Tuning Advisor does not recognize
interdependencies between the statements. Instead, SQL Tuning Advisor offers a
convenient way to get tuning recommendations for many statements.
Note:
Data visibility and privilege requirements may differ when using SQL Tuning
Advisor with pluggable databases. The advisor can tune a query in the current
pluggable database (PDB), and in other PDBs in which this query has been
executed. In this way, a container database (CDB) administrator can tune the
same query in many PDBs at the same time, whereas a PDB administrator can
only tune a single PDB.
See Also:
Optimizer
ADDM Automatic
Tuning
Optimizer
AWR
SQL Tuning
Advisor
Shared Pool
Inplementation
Shared SQL Area of SQL Profiles
(Automatic Only)
SELECT * FROM
employees
SQL AUTOTASK
Tuning
Set
• Automatically
You can configure SQL Tuning Advisor to run during nightly system maintenance
windows. When run by AUTOTASK, the advisor is known as Automatic SQL
Tuning Advisor and performs automatic SQL tuning. See “Managing the
Automatic SQL Tuning Task”.
• On-Demand
In on-demand SQL tuning, you manually invoke SQL Tuning Advisor to diagnose
and fix SQL-related performance problems after they have been discovered. Oracle
Enterprise Manager Cloud Control (Cloud Control) is the preferred interface for
tuning SQL on demand, but you can also use the DBMS_SQLTUNE PL/SQL
package. See “Running SQL Tuning Advisor On Demand”.
SQL Tuning Advisor uses Automatic Tuning Optimizer to perform its analysis. This
optimization is "automatic" because the optimizer analyzes the SQL instead of the
user. Do not confuse Automatic Tuning Optimizer with automatic SQL tuning, which
in this document refers only to the work performed by the Automatic SQL Tuning
task.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about
DBMS_SQLTUNE
• AWR
AWR takes regular snapshots of system activity, including high-load SQL
statements ranked by relevant statistics, such as CPU consumption and wait time.
You can view the AWR and manually identify high-load SQL statements. You can
run SQL Tuning Advisor on these statements, although Oracle Database
automatically performs this work as part of automatic SQL tuning. By default,
AWR retains data for the last eight days. You can locate and tune any high-load
SQL that ran within the retention period of AWR using this technique. See Oracle
Database Performance Tuning Guide to learn about AWR.
For example, assume that before tuning the execution time was 100 seconds, and after
implementing the recommendation the new execution time is expected to be 33
seconds. This benefit calculation for this performance improvement is as follows:
67% = (100 - 33)/(100)
You choose whether to accept the recommendations to optimize the SQL statements.
Depending on how it is configured, Automatic SQL Tuning Advisor can implement
the SQL profile recommendations to tune the statement without user intervention.
When invoked on demand, SQL Tuning Advisor can recommend that the user
implement a SQL profile, but can never implement it automatically.
Optimizer
Automatic Tuning
Optimizer
Normal Mode
Tuning Mode
SQL Tuning
Advisor
• Statistical Analysis
• SQL Profiling
See Also:
Statistical Analysis
The optimizer relies on object statistics to generate execution plans. If these statistics
are stale or missing, then the optimizer can generate suboptimal plans. Automatic
Tuning Optimizer checks each query object for missing or stale statistics, and
recommends gathering fresh statistics if needed. Figure 20-2 depicts the process of
statistical analysis.
SELECT . . .
SQL Tuning
Advisor
Optimizer
Automatic Tuning
Optimizer
Customers Customers
Table Table
Stale
Statistics Absent
Recommended collecting
object-level statistics Statistics
SQL Profiling
SQL profiling is the verification by the Automatic Tuning Optimizer of its own
estimates. By reviewing execution history and testing the SQL, the optimizer can
ensure that it has the most accurate information available to generate execution plans.
SQL profiling is related to but distinct from the steps of generating SQL Tuning
Advisor recommendations and implementing these recommendations.
The following graphic shows SQL Tuning Advisor recommending a SQL profile and
automatically implementing it. After the profile is created, the optimizer can use the
profile as additional input when generating execution plans.
SQL Tuning
Advisor SQL
Profile
Optimizer
(Tuning Mode)
Submit Create
Use
Database
Users
Optimizer
No application GB Well-Tuned
(Normal Mode)
code change Output Plan
HJ
HJ
See Also:
• DML statements (SELECT, INSERT with a SELECT clause, UPDATE, DELETE, and
the update or insert operations of MERGE)
SELECT . . .
SQL Tuning
Advisor
Optimizer
Automatic Tuning
Optimizer
SQL Profiling
* Reviews past execution history to
adjust settings
* Performs sampling or partial
execution
Recommendation
No Recommendation to Implement
SQL Profile
During SQL profiling, the optimizer verifies cost, selectivity, and cardinality for a
statement. The optimizer uses either of the following methods:
• When SQL Tuning Advisor is run on demand, the user must choose whether to
implement the SQL profile.
• When the Automatic SQL Tuning task is configured to implement SQL profiles
automatically, advisor behavior depends on the setting of the
ACCEPT_SQL_PROFILE tuning task parameter (see “Configuring the Automatic
SQL Tuning Task Using the Command Line”):
– If set to AUTO (default), then the setting is true when at least one SQL
statement exists with a SQL profile, and false when this condition is not
satisfied.
Note:
The Automatic SQL Tuning task cannot automatically create SQL plan
baselines or add plans to them (see “Plan Evolution”).
User must
choose whether
SQL Tuning On Demand to implement
Advisor
Recommends
Implementing
SQL profile No Autoimplementation
Autotask
Implements
SQL profile
Autoimplementation
At any time during or after automatic SQL tuning, you can view a report. This report
describes in detail the SQL statements that were analyzed, the recommendations
generated, and any SQL profiles that were automatically implemented.
See Also:
SELECT . . .
SQL Tuning
Advisor
Optimizer
Automatic Tuning
Optimizer
Recommends
Workload
SQL Access
Advisor
Index
Creation
Comprehensive
Analysis
Automatic Tuning Optimizer explores whether a new index can significantly enhance
query performance and recommends either of the following:
• Creating an index
Index recommendations are specific to the SQL statement processed by SQL
Tuning Advisor. Sometimes a new index provides a quick solution to the
performance problem associated with a single SQL statement.
SELECT . . . UNION
SQL Tuning
Advisor
Optimizer
Automatic Tuning
Optimizer
Restructured
• Design mistakes
A classic example of a design mistake is a missing join condition. If n is the number
of tables in a query block, then n-1 join conditions must exist to avoid a Cartesian
product.
In each case, Automatic Tuning Optimizer makes relevant suggestions to restructure
the statements. The suggested alternative statement is similar, but not equivalent, to
the original statement. For example, the suggested statement may use UNION ALL
instead of UNION. You can then determine if the advice is sound.
Optimizer
Automatic Tuning
Optimizer
Real-Time
Performance Data
GB Origin:
Cursor
Cache SQL Tuning
HJ Advisor
HJ
Searches Produces
Alternative Plan Finding
AWR Performance Summary
Recommendations
GB Origin:
STS
HJ
HJ
SQL Tuning Advisor validates the alternative execution plans and notes any plans that
are not reproducible. When reproducible alternative plans are found, you can create a
SQL plan baseline to instruct the optimizer to choose these plans in the future.
Example 20-1 Alternative Plan Finding
The following example shows an alternative plan finding for a SELECT statement:
2- Alternative Plan Finding
---------------------------
Some alternative execution plans for this statement were found by searching
the system's real-time and historical performance data.
The following table lists these plans ranked by their average elapsed time.
See section "ALTERNATIVE PLANS SECTION" for detailed information on each
plan.
Information
-----------
- The Original Plan appears to have the best performance, based on the
elapsed time per execution. However, if you know that one alternative
plan is better than the Original Plan, you can create a SQL plan baseline
for it. This will instruct the Oracle optimizer to pick it over any other
choices in the future.
execute dbms_sqltune.create_sql_plan_baseline(task_name => 'TASK_XXXXX',
object_id => 2, task_owner => 'SYS', plan_hash => xxxxxxxx);
The preceding example shows that SQL Tuning Advisor found two plans, one in the
shared SQL area and one in a SQL tuning set. The plan in the shared SQL area is the
same as the original plan.
SQL Tuning Advisor only recommends an alternative plan if the elapsed time of the
original plan is worse than alternative plans. In this case, SQL Tuning Advisor
recommends that users create a SQL plan baseline on the plan with the best
performance. In Example 20-1, the alternative plan did not perform as well as the
original plan, so SQL Tuning Advisor did not recommend using the alternative plan.
Example 20-2 Alternative Plans Section
In this example, the alternative plans section of the SQL Tuning Advisor output
includes both the original and alternative plans and summarizes their performance.
The most important statistic is elapsed time. The original plan used an index, whereas
the alternative plan used a full table scan, increasing elapsed time by .002 seconds.
Plan 1
------
Notes:
1. Statistics shown are averaged over multiple executions.
2. The plan matches the original plan.
--------------------------------------------
| Id | Operation | Name |
--------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | MERGE JOIN | |
| 3 | INDEX FULL SCAN | TEST1_INDEX |
| 4 | SORT JOIN | |
| 5 | TABLE ACCESS FULL| TEST |
--------------------------------------------
Plan 2
------
Buffer Gets :3
Disk Reads :0
Disk Writes :0
Notes:
1. Statistics shown are averaged over multiple executions.
-------------------------------------
| Id | Operation | Name |
-------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | HASH JOIN | |
| 3 | TABLE ACCESS FULL| TEST |
| 4 | TABLE ACCESS FULL| TEST1 |
-------------------------------------
See Also:
See Also:
Oracle Database Administrator's Guide to learn more about automated
maintenance tasks
• Ad hoc SQL statements or SQL statements that do not repeat within a week
• Parallel queries
• Queries that take too long to run after being SQL profiled, so that it is not practical
for SQL Tuning Advisor to test-execute them
• Recursive SQL
You can run SQL Tuning Advisor on demand to tune the preceding types of SQL
statements.
See Also:
Package Description
DBMS_AUTO_SQLTUNE Enables you run SQL Tuning Advisor, manage SQL
profiles, manage SQL tuning sets, and perform real-
time SQL performance monitoring. To use this API,
you must have the ADVISOR privilege.
See Also:
DBMS_SQLTUNE. DBMS_SQLTUNE.
SET_TUNING_TASK_PARAMETER REPORT_AUTO_TUNING_TASK
Enabling and Disabling the Automatic SQL Tuning Task Using Cloud Control
You can enable and disable all automatic maintenance tasks, including the Automatic
SQL Tuning task, using Cloud Control.
To enable or disable the Automatic SQL Tuning task using Cloud Control:
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
a. In the Task Settings for Automatic SQL Tuning, select either Enabled or
Disabled to enable or disable the automated task.
b. To disable Automatic SQL Tuning for specific days in the week, check the
appropriate box next to the window name.
d. Click Apply.
Enabling and Disabling the Automatic SQL Tuning Task from the Command Line
If you do not use Cloud Control to enable and disable the Automatic SQL Tuning task,
then you have the following options:
1. Connect SQL*Plus to the database with administrator privileges, and then do one
of the following:
CLIENT_NAME STATUS
-------------------- --------
sql tuning advisor ENABLED
1. Connect SQL*Plus to the database with administrator privileges, and then query
the current statistics level setting.
The following SQL*Plus command shows that STATISTICS_LEVEL is set to ALL:
sys@PROD> SHOW PARAMETER statistics_level
System altered.
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
Configuring the Automatic SQL Tuning Task Using the Command Line
The DBMS_AUTO_SQLTUNE package enables you to configure automatic SQL tuning
by specifying the task parameters using the SET_AUTO_TUNING_TASK_PARAMETER
procedure. Because the task is owned by SYS, only SYS can set task parameters.
The ACCEPT_SQL_PROFILE tuning task parameter specifies whether to implement
SQL profiles automatically (true) or require user intervention (false). The default is
AUTO, which means true if at least one SQL statement exists with a SQL profile and
false if this condition is not satisfied.
Note:
Assumptions
This tutorial assumes the following:
• You want the database to implement SQL profiles automatically, but to implement
no more than 50 SQL profiles per execution, and no more than 50 profiles total on
the database.
• You want the task to time out after 1200 seconds per execution.
1. Connect SQL*Plus to the database with the appropriate privileges, and then
optionally query the current task settings.
For example, connect SQL*Plus to the database with administrator privileges and
execute the following query:
COL PARAMETER_NAME FORMAT a25
COL VALUE FORMAT a10
(PARAMETER_NAME = 'LOCAL_TIME_LIMIT') OR
(PARAMETER_NAME = 'EXECUTION_DAYS_TO_EXPIRE') ) );
See Also:
Oracle Database PL/SQL Packages and Types Reference for complete reference
information for DBMS_AUTO_SQLTUNE
• General information
This section has a high-level description of the automatic SQL tuning task,
including information about the inputs given for the report, the number of SQL
statements tuned during the maintenance, and the number of SQL profiles created.
• Summary
This section lists the SQL statements (by their SQL identifiers) that were tuned
during the maintenance window and the estimated benefit of each SQL profile, or
the execution statistics after performing a test execution of the SQL statement with
the SQL profile.
• Tuning findings
This section contains the following information about each SQL statement analyzed
by SQL Tuning Advisor:
• Explain plans
This section shows the old and new explain plans used by each SQL statement
analyzed by SQL Tuning Advisor.
• Errors
This section lists all errors encountered by the automatic SQL tuning task.
Assumptions
This section assumes that you want to show all SQL statements that were analyzed in
the most recent execution, including recommendations that were not implemented.
1. Connect SQL*Plus to the database with administrator privileges, and then execute
the DBMS_SQLTUNE.REPORT_AUTO_TUNING_TASK function.
The following example generates a text report to show all SQL statements that
were analyzed in the most recent execution, including recommendations that
were not implemented:
VARIABLE my_rept CLOB;
BEGIN
:my_rept :=DBMS_SQLTUNE.REPORT_AUTO_TUNING_TASK (
begin_exec => NULL
, end_exec => NULL
, type => 'TEXT'
, level => 'TYPICAL'
, section => 'ALL'
, object_id => NULL
, result_limit => NULL
);
END;
PRINT :my_rept
2. Read the general information section for an overview of the tuning execution.
The following sample shows the Automatic SQL Tuning task analyzed 17 SQL
statements in just over 7 minutes:
MY_REPT
---------------------------------------------------------------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------
Tuning Task Name : SYS_AUTO_SQL_TUNING_TASK
Tuning Task Owner : SYS
Workload Type : Automatic High-Load SQL Workload
Execution Count : 6
Current Execution : EXEC_170
Execution Type : TUNE SQL
Scope : COMPREHENSIVE
Global Time Limit(seconds) : 3600
Per-SQL Time Limit(seconds) : 1200
Completion Status : COMPLETED
Started at : 04/16/2012 10:00:00
Completed at : 04/16/2012 10:07:11
Number of Candidate SQLs : 17
Cumulative Elapsed Time of SQL (s) : 8
---------------------------------------------------------------------------
DETAILS SECTION
---------------------------------------------------------------------------
Statements with Results Ordered by Max (Profile/Index) Benefit, Object ID
---------------------------------------------------------------------------
Object ID : 82
Schema Name: DBA1
SQL ID : dqjcc345dd4ak
SQL Text : SELECT status FROM dba_autotask_client WHERE client_name=:1
---------------------------------------------------------------------------
FINDINGS SECTION (1 finding)
---------------------------------------------------------------------------
Validation results
------------------
The SQL profile was tested by executing both its plan and the original
plan and measuring their respective execution statistics. A plan
may have been only partially executed if the other could be run
to completion in less time.
Notes
-----
1. The original plan was first executed to warm the buffer cache.
2. Statistics for original plan were averaged over next 9 executions.
3. The SQL profile plan was first executed to warm the buffer cache.
4. Statistics for the SQL profile plan were averaged over
next 9 executions.
• You proactively run ADDM, which reports that some SQL statements do not meet
your performance requirements.
• You reactively tune SQL statement because users complain about suboptimal SQL
performance.
In both situations, running SQL Tuning Advisor is usually the quickest way to fix
unexpected SQL performance problems.
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
2. From the Performance menu, click SQL, then SQL Tuning Advisor.
The Schedule SQL Tuning Advisor page appears.
3. See Oracle Database 2 Day + Performance Tuning Guide to learn how to configure
and run SQL Tuning Advisor using Cloud Control.
See Also:
Oracle Database PL/SQL Packages and Types Reference for complete reference
information
STS
create_tuning_task
set_tuning_task_parameter
execute_tuning_task
Monitor Task
report_tuning_task
Implement
Recommendations
1. Prepare or create the input to SQL Tuning Advisor. The input can be either:
• A SQL statement selected by SQL identifier from the shared SQL area
• LIMITED
SQL Tuning Advisor produces recommendations based on statistical checks, access
path analysis, and SQL structure analysis. SQL profile recommendations are not
generated.
• COMPREHENSIVE
SQL Tuning Advisor carries out all the analysis it performs under limited scope
plus SQL profiling.
Assumptions
This tutorial assumes the following:
• You want to tune as user hr, who has the ADVISOR privilege.
• You want to pass the bind variable 100 to the preceding query.
1. Connect SQL*Plus to the database with the appropriate privileges, and then run
the DBMS_SQLTUNE.CREATE_TUNING_TASK function.
For example, execute the following PL/SQL program:
DECLARE
my_task_name VARCHAR2(30);
my_sqltext CLOB;
BEGIN
my_sqltext := 'SELECT /*+ ORDERED */ * ' ||
'FROM employees e, locations l, departments d ' ||
'WHERE e.department_id = d.department_id AND ' ||
my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK (
sql_text => my_sqltext
, bind_list => sql_binds(anydata.ConvertNumber(100))
, user_name => 'HR'
, scope => 'COMPREHENSIVE'
, time_limit => 60
, task_name => 'STA_SPECIFIC_EMP_TASK'
, description => 'Task to tune a query on a specified employee'
);
END;
/
In the preceding output, the INITIAL status indicates that the task has not yet
started execution.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SQLTUNE.CREATE_TUNING_TASK function
Assumptions
This tutorial assumes the following:
• You want to tune as user hr, who has the ADVISOR privilege.
• You want to change the maximum time that the SQL tuning task can run to 300
seconds.
1. Connect SQL*Plus to the database with the appropriate privileges, and then run
the DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER function.
For example, execute the following PL/SQL program to change the time limit of
the tuning task to 300 seconds:
BEGIN
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER (
task_name => 'STA_SPECIFIC_EMP_TASK'
, parameter => 'TIME_LIMIT'
, value => 300
);
END;
/
Note:
You can also execute the automatic tuning task
SYS_AUTO_SQL_TUNING_TASK using the EXECUTE_TUNING_TASK API. SQL
Tuning Advisor performs the same analysis and actions as it would when run
automatically.
Assumptions
This tutorial assumes the following:
• You want to tune as user hr, who has the ADVISOR privilege.
1. Connect SQL*Plus to the database with the appropriate privileges, and then run
the DBMS_SQLTUNE.EXECUTE_TUNING_TASK function.
For example, execute the following PL/SQL program:
BEGIN
DBMS_SQLTUNE.EXECUTE_TUNING_TASK(task_name=>'STA_SPECIFIC_EMP_TASK');
END;
/
See Also:
Oracle Database PL/SQL Packages and Types Reference for complete reference
information about the DBMS_SQLTUNE.EXECUTE_TUNING_TASK function
View Description
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database with the appropriate privileges, and then
determine whether the task is executing or completed.
For example, query the status of STA_SPECIFIC_EMP_TASK as follows:
SELECT STATUS
FROM USER_ADVISOR_TASKS
WHERE TASK_NAME = 'STA_SPECIFIC_EMP_TASK';
See Also:
Assumptions
This tutorial assumes the following:
• You want to tune as user hr, who has the ADVISOR privilege.
1. Connect SQL*Plus to the database with the appropriate privileges, and then run
the DBMS_SQLTUNE.REPORT_TUNING_TASK function.
For example, you run the following statements:
SET LONG 1000
SET LONGCHUNKSIZE 1000
SET LINESIZE 100
SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( 'STA_SPECIFIC_EMP_TASK' )
FROM DUAL;
---------------------------------------------------------------------------
Schema Name: HR
SQL ID : dg7nfaj0bdcvk
SQL Text : SELECT /*+ ORDERED */ * FROM employees e, locations l,
departments d WHERE e.department_id = d.department_id AND
l.location_id = d.location_id AND e.employee_id < :bnd
Bind Variables :
1 - (NUMBER):100
---------------------------------------------------------------------------
FINDINGS SECTION (4 findings)
-----------------------------------------------
See Also:
Oracle Database PL/SQL Packages and Types Reference for complete reference
information
Note:
Data visibility and privilege requirements may differ when using SQL Access
Advisor with pluggable databases. See Oracle Database Administrator's Guide
for a table that summarizes how manageability features work in a container
database (CDB).
See Also:
Oracle Database 2 Day + Performance Tuning Guide to learn how to use SQL
Access Advisor with Cloud Control
Hypothetical Optimizer
Automatic
Tuning
Shared Pool Optimizer
Library Cache
Materialized
Views
SQL Materialized
Tuning View Logs
Set
Partitions
DBA
See Also:
Note:
For best results, provide a workload as a SQL tuning set. The DBMS_SQLTUNE
package provides helper functions that can create SQL tuning sets from
common workload sources, such as the SQL cache, a user-defined workload
stored in a table, and a hypothetical workload.
• Hypothetical workload
You can create a hypothetical workload from a schema by analyzing dimensions
and constraints. This option is useful when you are initially designing your
application.
See Also:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_ADVISOR.SET_TASK_PARAMETER procedure
• Indexes
SQL Access Advisor index recommendations include bitmap, function-based, and
B-tree indexes. A bitmap index offers a reduced response time for many types of ad
hoc queries and reduced storage requirements compared to other indexing
techniques. B-tree indexes are most commonly used in a data warehouse to index
unique or near-unique keys. SQL Access Advisor materialized view
recommendations include fast refreshable and full refreshable MVs, for either
general rewrite or exact text match rewrite.
• Materialized views
SQL Access Advisor, using the TUNE_MVIEW procedure, also recommends how to
optimize materialized views so that they can be fast refreshable and take advantage
of general query rewrite.
• Partitions
SQL Access Advisor can recommend partitioning on an existing unpartitioned base
table to improve performance. Furthermore, it may recommend new indexes and
materialized views that are themselves partitioned.
While creating new partitioned indexes and materialized view is no different from
the unpartitioned case, partition existing base tables with care. This is especially
true when indexes, views, constraints, or triggers are defined on the table.
To make recommendations, SQL Access Advisor relies on structural statistics about
table and index cardinalities of dimension level columns, JOIN KEY columns, and fact
table key columns. You can gather exact or estimated statistics with the DBMS_STATS
package (see “About Manual Statistics Collection with DBMS_STATS”).
Because gathering statistics is time-consuming and full statistical accuracy is not
required, it is usually preferable to estimate statistics. Without gathering statistics on a
specified table, queries referencing this table are marked as invalid in the workload,
resulting in no recommendations for these queries. It is also recommended that all
existing indexes and materialized views have been analyzed.
See Also:
• Oracle Database VLDB and Partitioning Guide to learn more about partitions
Types of Actions
SQL Access Advisor recommendations include the following types of actions:
• GATHER STATS
This action generates a call to a DBMS_STATS procedure to gather statistics on a
newly generated access structure (see “About Manual Statistics Collection with
DBMS_STATS”).
Multiple recommendations may refer to the same action. However, when generating a
script for the recommendation, you only see each action once.
See Also:
“Viewing SQL Access Advisor Task Results” to learn how to view actions and
recommendations
SQL Access Advisor may recommend partitioning an existing unpartitioned base table
to improve query performance. When the advisor implementation script contains
partition recommendations, note the following issues:
• Partitioning an existing table is a complex and extensive operation, which may take
considerably longer than implementing a new index or materialized view.
Sufficient time should be reserved for implementing this recommendation.
• While repartitioning a base table, SQL Access Advisor scripts make a temporary
copy of the original table, which occupies the same amount of space as the original
table. Therefore, the repartitioning process requires sufficient free disk space for
another copy of the largest table to be repartitioned. Ensure that such space is
available before running the implementation script.
The partition implementation script attempts to migrate dependent objects such as
indexes, materialized views, and constraints. However, some object cannot be
automatically migrated. For example, PL/SQL stored procedures defined against a
repartitioned base table typically become invalid and must be recompiled.
See Also:
Oracle Database SQL Language Reference for CREATE DIRECTORY syntax, and
Oracle Database PL/SQL Packages and Types Reference for detailed information
about the GET_TASK_SCRIPT procedure.
You can also invoke SQL Access Advisor through the DBMS_ADVISOR package. This
chapter explains how to use the API. See Oracle Database PL/SQL Packages and Types
Reference for complete semantics and syntax.
Accessing the SQL Tuning Advisor: Initial Options Page Using Cloud Control
The SQL Access Advisor: Initial Options page in Cloud Control is the starting page for
a wizard that guides you through the process of obtaining recommendations.
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
2. From the Performance menu, select SQL, then SQL Access Advisor.
The SQL Access Advisor: Initial Options page appears., shown in Figure 21-2.
You can perform most SQL plan management tasks in this page or in pages
accessed through this page.
See Also:
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about
DBMS_ADVISOR
Typically, you use SQL Access Advisor by performing the following steps:
Prerequisites
The user creating the STS must have been granted the ADMINISTER SQL TUNING
SET privilege. To run SQL Access Advisor on SQL tuning sets owned by other users,
the user must have the ADMINISTER ANY SQL TUNING SET privilege.
Assumptions
This tutorial assumes the following:
• You want to use this STS as input for a workload derived from the sh schema.
To create an STS :
1. Connect SQL*Plus to the database as user sh, and then set SQL*Plus variables.
For example, enter the following commands:
CONNECT SH
Password: ********
SET SERVEROUTPUT ON;
VARIABLE task_id NUMBER;
VARIABLE task_name VARCHAR2(255);
VARIABLE workload_name VARCHAR2(255);
See Also:
Procedure Description
Assumptions
This tutorial assumes that you want to do the following:
• Load the sh.user_workload table with information about three queries of tables
in the sh schema
• Populate the STS created in “Creating a SQL Tuning Set as Input for SQL Access
Advisor” with the workload contained in sh.user_workload
1. Connect SQL*Plus to the database as user sh, and then create the
user_workload table.
For example, enter the following commands:
DROP TABLE user_workload;
CREATE TABLE user_workload
(
username varchar2(128), /* User who executes statement */
module varchar2(64), /* Application module name */
action varchar2(64), /* Application action name */
elapsed_time number, /* Elapsed time for query */
cpu_time number, /* CPU time for query */
buffer_gets number, /* Buffer gets consumed by query */
disk_reads number, /* Disk reads consumed by query */
rows_processed number, /* # of rows processed by query */
executions number, /* # of times query executed */
optimizer_cost number, /* Optimizer cost for query */
priority number, /* User-priority (1,2 or 3) */
last_execution_date date, /* Last time query executed */
stat_period number, /* Window exec time in seconds */
sql_text clob /* Full SQL Text */
);
-- order by
INSERT INTO user_workload (username, module, action, priority, sql_text)
3. Execute a PL/SQL program that fills a cursor with rows from the
user_workload table, and then loads the contents of this cursor into the STS
named MY_STS_WORKLOAD.
For example, execute the following PL/SQL program:
DECLARE
sqlset_cur DBMS_SQLTUNE.SQLSET_CURSOR;
BEGIN
OPEN sqlset_cur FOR
SELECT SQLSET_ROW(null,null, SQL_TEXT, null, null, 'SH', module,
'Action', 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, null, 2, 3,
sysdate, 0, 0, null, 0, null, null)
FROM USER_WORKLOAD;
DBMS_SQLTUNE.LOAD_SQLSET('MY_STS_WORKLOAD', sqlset_cur);
END;
/
Assumptions
This tutorial assumes the following:
• You want to use this task to analyze the workload that you defined in “Populating
a SQL Tuning Set with a User-Defined Workload”.
• You want to terminate the task if it takes longer than 30 minutes to execute.
1. Connect SQL*Plus to the database as user sh, and then create the task.
For example, enter the following commands:
EXECUTE :task_name := 'MYTASK';
EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, :task_name);
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
CREATE_TASK procedure and its parameters
• Oracle Database PL/SQL Packages and Types Reference to learn about the
SET_TASK_PARAMETER procedure and its parameters
• Oracle Database PL/SQL Packages and Types Reference to learn about the
ADD_STS_REF procedure and its parameters
completed, or the database detects a user interrupt. After the return or execution of the
task, you can check the DBA_ADVISOR_LOG table for the execution status.
Running EXECUTE_TASK generates recommendations. A recommendation includes
one or more actions, such as creating a materialized view log or a materialized view.
To avoid missing critical workload queries, the current database user must have
SELECT privileges on the tables targeted for materialized view analysis. For these
tables, these SELECT privileges cannot be obtained through a role.
Assumptions
This tutorial assumes that you want to execute the task you configured in “Creating
and Configuring a SQL Access Advisor Task”.
1. Connect SQL*Plus to the database as user sh, and then execute the task.
For example, execute the following statement:
EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name);
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about the
EXECUTE_TASK procedure and its parameters
Assumptions
This tutorial assumes that you want to view results of the task you executed in
“Executing a SQL Access Advisor Task”.
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the advisor recommendations.
For example, execute the following statements (sample output included):
VARIABLE workload_name VARCHAR2(255);
VARIABLE task_name VARCHAR2(255);
EXECUTE :task_name := 'MYTASK';
EXECUTE :workload_name := 'MY_STS_WORKLOAD';
The precost and postcost numbers are in terms of the estimated optimizer cost
(shown in EXPLAIN PLAN) both without and with the recommended access
structure changes.
'ACTIONCOUNT CNT
------------ ----------
Action Count 4
See Also:
Oracle Database PL/SQL Packages and Types Reference for details regarding
Attr5 and Attr6
Assumptions
This tutorial assumes that you want to save and execute a script that contains the
recommendations generated in “Executing a SQL Access Advisor Task”.
2. Create a directory object and grant permissions to read and write to it.
For example, use the following statements:
CREATE DIRECTORY ADVISOR_RESULTS AS '/tmp';
GRANT READ ON DIRECTORY ADVISOR_RESULTS TO PUBLIC;
GRANT WRITE ON DIRECTORY ADVISOR_RESULTS TO PUBLIC;
3. Connect to the database as sh, and then save the script to a file.
For example, use the following statement:
EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('MYTASK'),
'ADVISOR_RESULTS', 'advscript.sql');
Rem
Rem Repartitioning table "SH"."SALES"
Rem
SET SERVEROUTPUT ON
SET ECHO ON
Rem
Rem Creating new partitioned table
Rem
CREATE TABLE "SH"."SALES1"
( "PROD_ID" NUMBER,
"CUST_ID" NUMBER,
"TIME_ID" DATE,
"CHANNEL_ID" NUMBER,
"PROMO_ID" NUMBER,
"QUANTITY_SOLD" NUMBER(10,2),
"AMOUNT_SOLD" NUMBER(10,2)
) PCTFREE 5 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS NOLOGGING
TABLESPACE "EXAMPLE"
PARTITION BY RANGE ("TIME_ID") INTERVAL( NUMTOYMINTERVAL( 1, 'MONTH'))
( PARTITION VALUES LESS THAN (TO_DATE(' 1998-02-01 00:00:00',
'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) );
.
.
.
See Also:
Oracle Database SQL Language Reference for CREATE DIRECTORY syntax, and
Oracle Database PL/SQL Packages and Types Reference to learn about the
GET_TASK_SCRIPT procedure
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database as user sh, and then initialize SQL*Plus
variables for the SQL statement and task name.
For example, enter the following commands:
VARIABLE t_name VARCHAR2(255);
VARIABLE sq VARCHAR2(4000);
EXEC :sq := 'SELECT COUNT(*) FROM customers WHERE cust_state_province =''CA''';
EXECUTE :t_name := 'MY_QUICKTUNE_TASK';
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about the
QUICK_TUNE procedure and its parameters
1. Connect SQL*Plus to the database with the appropriate privileges, and then create
a task.
For example, enter the following statement, where t_name is a SQL*Plus variable
set to the name of the task:
EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:t_name);
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
SET_TASK_PARAMETER procedure and its parameters
• Make the task a template upon which you can define other tasks (see “Creating and
Using SQL Access Advisor Task Templates”).
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database as user sh, and then change the name of the
task.
For example, use the following statement:
EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('MYTASK', 'TUNING1');
See Also:
Oracle Database PL/SQL Packages and Types Reference for more information
regarding the UPDATE_TASK_ATTRIBUTES procedure and its parameters
Procedure Description
Procedure Description
Assumptions
This tutorial assumes the following:
• You want to set naming conventions for indexes and materialized views that are
recommended by tasks based on MY_TEMPLATE.
1. Connect SQL*Plus to the database as user sh, and then create a task as a template.
For example, create a template named MY_TEMPLATE as follows:
VARIABLE template_id NUMBER;
VARIABLE template_name VARCHAR2(255);
EXECUTE :template_name := 'MY_TEMPLATE';
BEGIN
DBMS_ADVISOR.CREATE_TASK (
'SQL Access Advisor'
, :template_id
, :template_name
, is_template => 'true'
);
END;
);
END;
BEGIN
DBMS_ADVISOR.SET_TASK_PARAMETER (
:template_name
, 'MVIEW_NAME_TEMPLATE'
, 'SH_MV$$_<SEQ>'
);
END;
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
CREATE_TASK procedure and its parameters
• Oracle Database PL/SQL Packages and Types Reference to learn about the
SET_TASK_PARAMETER procedure and its parameters
Assumptions
This tutorial assumes the following:
• You want to interrupt this task, and then view the recommendations.
1. Connect SQL*Plus to the database as sh, and then interrupt the task.
For example, create a template named MY_TEMPLATE as follows:
EXECUTE DBMS_ADVISOR.INTERRUPT_TASK ('MYTASK');
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
INTERRUPT_TASK procedure
The RESET_TASK procedure resets a task to its initial starting point, which has the
effect of removing all recommendations and intermediate data from the task. The task
status is set to INITIAL. The syntax is as follows:
DBMS_ADVISOR.RESET_TASK (task_name IN VARCHAR2);
Assumptions
This tutorial assumes the following:
• You want to cancel this task, and then reset it so that the task makes only index
recommendations.
1. Connect SQL*Plus to the database as user sh, and then cancel the task.
For example, create a template named MY_TEMPLATE as follows:
EXECUTE DBMS_ADVISOR.CANCEL_TASK ('MYTASK');
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn more about the
RESET_TASK procedure and its parameters
• Oracle Database PL/SQL Packages and Types Reference to learn more about the
CANCEL_TASK procedure and its parameters
If a task is linked to an STS workload, and if you want to delete the task or workload,
then you must remove the link between the task and the workload using the
DELETE_STS_REF procedure. The following example deletes the link between task
MYTASK and the current user's SQL tuning set MY_STS_WORKLOAD:
EXECUTE DBMS_ADVISOR.DELETE_STS_REF('MYTASK', null, 'MY_STS_WORKLOAD');
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database as user sh, and then query existing SQL Access
Advisor tasks.
For example, query the data dictionary as follows (sample output included):
SELECT TASK_NAME
FROM USER_ADVISOR_TASKS
WHERE ADVISOR_NAME = 'SQL Access Advisor';
TASK_NAME
-------------------------
MYTASK
NEWTASK
See Also:
Assumptions
This tutorial assumes the following:
To mark a recommendation:
1. Connect SQL*Plus to the database as user sh, and then mark the
recommendation.
For example, reject recommendation 1 as follows:
EXECUTE DBMS_ADVISOR.MARK_RECOMMENDATION('MYTASK', 1, 'REJECT');
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about the
MARK_RECOMMENDATIONS procedure and its parameters
• OWNER
Specifies the owner name of the recommended object.
• NAME
Specifies the name of the recommended object.
• TABLESPACE
Specifies the tablespace of the recommended object.
Assumptions
This tutorial assumes the following:
To mark a recommendation:
1. Connect SQL*Plus to the database as user sh, and then update the
recommendation attribute.
For example, change the tablespace name to SH_MVIEWS as follows:
BEGIN
DBMS_ADVISOR.UPDATE_REC_ATTRIBUTES (
'MYTASK'
, 1
, 1
, 'TABLESPACE'
, 'SH_MVIEWS'
);
END;
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn more about the
UPDATE_REC_ATTRIBUTES procedure and its parameters
Table 21-5 (Cont.) Types of Advisor Task Parameters And Their Uses
START_TIME STORAGE_CHANGE
TIME_LIMIT USE_SEPARATE_TABLES
PACES
VALID_ACTION_LIST WORKLOAD_SCOPE
VALID_MODULE_LIST
VALID_SQLSTRING_LIST
VALID_TABLE_LIST
VALID_USERNAME_LIST
Constant Description
ADVISOR_ALL A value that indicates all possible values. For string parameters,
this value is equivalent to the wildcard % character.
ADVISOR_DEFAULT Indicates the default value. Typically used when setting task or
workload parameters.
SQLACCESS_OLTP Specifies the name of a default SQL Access OLTP task template.
This template sets the DML_VOLATILITY task parameter to true
and ANALYSIS_SCOPE to INDEX.
Constant Description
SQLACCESS_ADVISOR Contains the formal name of SQL Access Advisor. You can
specify this name when procedures require the Advisor name as
an argument.
This part explains how to manage SQL profiles and SQL plan baselines, and migrate
stored outlines to SQL plan baselines.
contains the following chapters:
• Unlike hints and stored outlines, SQL profiles do not tie the optimizer to a specific
plan or subplan. SQL profiles fix incorrect estimates while giving the optimizer the
flexibility to pick the best plan in different situations.
• Unlike hints, no changes to application source code are necessary when using SQL
profiles. The use of SQL profiles by the database is transparent to the user.
See Also:
“Influencing the Optimizer with Hints”
Note:
The SQL profile contains supplemental statistics for the entire statement, not
individual plans. The profile does not itself determine a specific plan.
A SQL profile contains, among other statistics, a set of cardinality adjustments. The
cardinality measure is based on sampling the WHERE clause rather than on statistical
projection. A profile uses parts of the query to determine whether the estimated
cardinalities are close to the actual cardinalities and, if a mismatch exists, uses the
corrected cardinalities. For example, if a SQL profile exists for SELECT * FROM t
WHERE x=5 AND y=10, then the profile stores the actual number of rows returned.
When choosing plans, the optimizer has the following sources of information:
• The environment, which contains the database configuration, bind variable values,
optimizer statistics, data set, and so on
SELECT . . . GB
HJ
HJ
Environment GB
Optimizer
Statistics Data NL
Set NL
Bind Configuration
Variables
If either the optimizer environment or SQL profile change, then the optimizer can
create a new plan. As tables grow, or as indexes are created or dropped, the plan for a
SQL profile can change. The profile continues to be relevant even if the data
See Also:
See Also:
• Oracle Database VLDB and Partitioning Guide to learn more about Auto DOP
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SQLTUNE.ACCEPT_SQL_PROFILE procedure
------------------------------------------
- Consider accepting the recommended SQL profile.
execute dbms_sqltune.accept_sql_profile(task_name => 'my_task',
object_id => 3, task_owner => 'SH', replace => TRUE);
Validation results
------------------
The SQL profile was tested by executing both its plan and the original plan
and measuring their respective execution statistics. A plan may have been
only partially executed if the other could be run to completion in less time.
Notes
-----
1. The SQL profile plan was first executed to warm the buffer cache.
2. Statistics for the SQL profile plan were averaged over next 3 executions.
Sometimes SQL Tuning Advisor may recommend implementing a profile that uses the
Automatic Degree of Parallelism (Auto DOP) feature. A parallel query profile is only
recommended when the original plan is serial and when parallel execution can
significantly reduce the elapsed time for a long-running query.
When it recommends a profile that uses Auto DOP, SQL Tuning Advisor gives details
about the performance overhead of using parallel execution for the SQL statement in
the report. For parallel execution recommendations, SQL Tuning Advisor may provide
two SQL profile recommendations, one using serial execution and one using parallel.
The following example shows a parallel query recommendation. In this example, a
degree of parallelism of 7 improves response time significantly at the cost of increasing
resource consumption by almost 25%. You must decide whether the reduction in
database throughput is worth the increase in response time.
Recommendation (estimated benefit: 99.99%)
------------------------------------------
- Consider accepting the recommended SQL profile to use parallel execution
for this statement.
execute dbms_sqltune.accept_sql_profile(task_name => 'gfk_task',
object_id => 3, task_owner => 'SH', replace => TRUE,
profile_type => DBMS_SQLTUNE.PX_PROFILE);
Executing this query parallel with DOP 7 will improve its response time
82.22% over the SQL profile plan. However, there is some cost in enabling
parallel execution. It will increase the statement's resource consumption by
an estimated 24.43% which may result in a reduction of system throughput.
Also, because these resources are consumed over a much smaller duration, the
response time of concurrent statements might be negatively impacted if
sufficient hardware capacity is not available.
The following data shows some sampled statistics for this SQL from the past
See Also:
See Also:
• Oracle Database PL/SQL Packages and Types Reference for information about
the DBMS_SQLTUNE package
DBMS_SQLTUNE.
DBA_SQL_PROFILES
ALTER_SQL_PROFILE
See Also:
Oracle Database PL/SQL Packages and Types Reference for information about the
DBMS_SQLTUNE package
• profile_type
Set this parameter to REGULAR_PROFILE for a SQL profile without a change to
parallel execution, or PX_PROFLE for a SQL profile with a change to parallel
execution.
• force_match
This parameter controls statement matching. Typically, an accepted SQL profile is
associated with the SQL statement through a SQL signature that is generated using
a hash function. This hash function changes the SQL statement to upper case and
removes all extra whites spaces before generating the signature. Thus, the same
SQL profile works for all SQL statements in which the only difference is case and
white spaces.
By setting force_match to true, the SQL profile additionally targets all SQL
statements that have the same text after the literal values in the WHERE clause have
been replaced by bind variables. This setting may be useful for applications that
use only literal values because it enables SQL with text differing only in its literal
values to share a SQL profile. If both literal values and bind variables are in the
SQL text, or if force_match is set to false (default), then the literal values in the
WHERE clause are not replaced by bind variables.
See Also:
Oracle Database PL/SQL Packages and Types Reference for information about the
ACCEPT_SQL_PROFILE procedure
Assumptions
This tutorial assumes the following:
• The PL/SQL block accepts a profile that uses parallel execution (profile_type).
• Connect SQL*Plus to the database with the appropriate privileges, and then
execute the ACCEPT_SQL_PROFILE function.
For example, execute the following PL/SQL:
DECLARE
my_sqlprofile_name VARCHAR2(30);
BEGIN
my_sqlprofile_name := DBMS_SQLTUNE.ACCEPT_SQL_PROFILE (
task_name => 'STA_SPECIFIC_EMP_TASK'
, name => 'my_sql_profile'
, profile_type => DBMS_SQLTUNE.PX_PROFILE
, force_match => true
);
END;
/
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SQLTUNE.ACCEPT_SQL_PROFILE procedure
• Connect SQL*Plus to the database with the appropriate privileges, and then query
the DBA_SQL_PROFILES view.
For example, execute the following query:
COLUMN category FORMAT a10
COLUMN sql_text FORMAT a20
See Also:
1. Connect SQL*Plus to the database with the appropriate privileges, and then use
the ALTER_SQL_PROFILE procedure to set the attribute_name.
For example, execute the following code to set the attribute CATEGORY to TEST:
VARIABLE pname my_sql_profile
BEGIN DBMS_SQLTUNE.ALTER_SQL_PROFILE (
name => :pname
, attribute_name => 'CATEGORY'
, value => 'TEST'
);
END;
);
END;
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
ALTER_SQL_PROFILE procedure
Assumptions
This section assumes the following:
• You want to ignore errors raised if the name does not exist.
• Connect SQL*Plus to the database with the appropriate privileges, call the
DBMS_SQLTUNE.DROP_SQL_PROFILE procedure.
The following example drops the profile named my_sql_profile:
BEGIN
DBMS_SQLTUNE.DROP_SQL_PROFILE (
name => 'my_sql_profile'
);
END;
/
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DROP_SQL_PROFILE procedure
CREATE_STGTAB_SQLPROF Creates the staging table used for copying SQL profiles
from one system to another.
PACK_STGTAB_SQLPROF Moves profile data out of the SYS schema into the
staging table.
The following graphic shows the basic workflow of transporting SQL profiles:
DBMS_SQLTUNE Accept a
ACCEPT_SQL_PROFILE SQL Profile
CREATE_STGTAB_SQLPROF
PACK_STGTAB_SQLPROF
Transport
Transport SQL Profile to different
database
UNPACK_STGTAB_SQLPROF
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database with the appropriate privileges, and then use
the CREATE_STGTAB_SQLPROF procedure to create a staging table to hold the
SQL profiles.
The following example creates my_staging_table in the dba1 schema:
BEGIN
DBMS_SQLTUNE.CREATE_STGTAB_SQLPROF (
table_name => 'my_staging_table'
, schema_name => 'dba1'
);
END;
/
3. Move the staging table to the database where you plan to unpack the SQL
profiles.
Move the table using your utility of choice. For example, use Oracle Data Pump or
a database link.
4. On the database where you plan to import the SQL profiles, use
UNPACK_STGTAB_SQLPROF to unpack SQL profiles from the staging table.
The following example shows how to unpack SQL profiles in the staging table:
BEGIN
DBMS_SQLTUNE.UNPACK_STGTAB_SQLPROF(
replace => true
, staging_table_name => 'my_staging_table'
);
END;
/
See Also:
• Oracle Database PL/SQL Packages and Types Reference for complete reference
information about DBMS_SQLTUNE
This chapter explains the concepts and tasks relating to SQL plan management using
the DBMS_SPM package.
This chapter contains the following topics:
See Also:
• Plan capture
This component stores relevant information about plans for a set of SQL
statements. See “Plan Capture”.
• Plan selection
This component is the detection by the optimizer of plan changes based on stored
plan history, and the use of SQL plan baselines to select appropriate plans to avoid
potential performance regressions. See “Plan Selection”.
• Plan evolution
This component is the process of adding new plans to existing SQL plan baselines,
either manually or automatically. See “Plan Evolution”.
This section contains the following topics:
• Plan Capture
• Plan Selection
• Plan Evolution
Note:
SQL plan baselines cannot help when an event has caused irreversible
execution plan changes, such as dropping an index.
• A database upgrade that installs a new optimizer version usually results in plan
changes for a small percentage of SQL statements.
Most plan changes result in either improvement or no performance change.
However, some plan changes may cause performance regressions. SQL plan
baselines significantly minimize potential regressions resulting from an upgrade.
When you upgrade, the database only uses plans from the plan baseline. The
database puts new plans that are not in the current baseline into a holding area,
and later evaluates them to determine whether they use fewer resources than the
current plan in the baseline. If the plans perform better, then the database promotes
them into the baseline; otherwise, the database does not promote them.
• Ongoing system and data changes can affect plans for some SQL statements,
potentially causing performance regressions.
SQL plan baselines help minimize performance regressions and stabilize SQL
performance.
• Deployment of new application modules introduces new SQL statements into the
database.
The application software may use appropriate SQL execution plans developed in a
standard test configuration for the new statements. If the system configuration is
significantly different from the test configuration, then the database can evolve
SQL plan baselines over time to produce better performance.
See Also:
Oracle Database Upgrade Guide to learn how to upgrade an Oracle database
• In general, SQL plan baselines are proactive, whereas SQL profiles are reactive.
Typically, you create SQL plan baselines before significant performance problems
occur. SQL plan baselines prevent the optimizer from using suboptimal plans in
the future.
The database creates SQL profiles when you invoke SQL Tuning Advisor, which
you do typically only after a SQL statement has shown high-load symptoms. SQL
profiles are primarily useful by providing the ongoing resolution of optimizer
mistakes that have led to suboptimal plans. Because the SQL profile mechanism is
reactive, it cannot guarantee stable performance as drastic database changes occur.
The following graphic illustrates the difference:
Suboptimal Corrects
SQL Profile
Plan Cause
• SQL plan baselines reproduce a specific plan, whereas SQL profiles correct
optimizer cost estimates.
A SQL plan baseline is a set of accepted plans. Each plan is implemented using a
set of outline hints that fully specify a particular plan. SQL profiles are also
implemented using hints, but these hints do not specify any specific plan. Rather,
the hints correct miscalculations in the optimizer estimates that lead to suboptimal
plans. For example, a hint may correct the cardinality estimate of a table.
Because a profile does not constrain the optimizer to any one plan, a SQL profile is
more flexible than a SQL plan baseline. For example, changes in initialization
parameters and optimizer statistics allow the optimizer to choose a better plan.
Oracle recommends that you use SQL Tuning Advisor. In this way, you follow the
recommendations made by the advisor for SQL profiles and plan baselines rather than
trying to determine which mechanism is best for each SQL statement.
See Also:
Plan Capture
SQL plan capture refers to techniques for capturing and storing relevant information
about plans in the SQL Management Base for a set of SQL statements. Capturing a
plan means making SQL plan management aware of this plan.
You can configure initial plan capture to occur automatically by setting an
initialization parameter, or you can capture plans manually by using the DBMS_SPM
package.
• If a SQL plan baseline does not exist, then the optimizer creates a plan history and
SQL plan baseline for the statement, marking the initial plan for the statement as
accepted and adding it to the SQL plan baseline.
• If a SQL plan baseline exists, then the optimizer behavior depends on the cost-
based plan derived at parse time:
– If this plan does not match a plan in the SQL plan baseline, then the optimizer
marks the new plan as unaccepted and adds it to the SQL plan baseline.
– If this plan does match a plan in the SQL plan baseline, then nothing is added to
the SQL plan baseline.
The following graphic shows the decision tree for automatic initial plan capture when
OPTIMIZER_USE_SQL_PLAN_BASELINES is set to true (see “Plan Selection” for
more information):
SQL is issued
Yes
No No No
Note:
See Also:
Shared Pool
Library Cache
SQL Management Base
Shared SQL Area
SQL Statement Log
SELECT * FROM
employees SQL Plan History
GB
accepted
enabled
Staging Table HJ
HJ
Stored Outline
/*+ hint */
/*+ hint */
/*+ hint */
The loading behavior varies depending on whether a SQL plan baseline exists for each
statement represented in the bulk load:
• If a baseline for the statement does not exist, then the database does the following:
• If a baseline for the statement exists, then the database does the following:
2. Adds the plan to the plan baseline for the statement without verifying the
plan's performance
Manually loaded plans are always marked accepted because the optimizer assumes
that any plan loaded manually by the administrator has acceptable performance.
Plan Selection
SQL plan selection is the optimizer ability to detect plan changes based on stored plan
history, and the use of SQL plan baselines to select plans to avoid potential
performance regressions.
When the database performs a hard parse of a SQL statement, the optimizer generates
a best-cost plan. By default, the optimizer then attempts to find a matching plan in the
SQL plan baseline for the statement. If no plan baseline exists, then the database runs
the statement with the best-cost plan.
If a plan baseline exists, then the optimizer behavior depends on whether the newly
generated plan is in the plan baseline:
• If the new plan is in the baseline, then the database executes the statement using
the found plan.
• If the new plan is not in the baseline, then the optimizer marks the newly generated
plan as unaccepted and adds it to the plan history. Optimizer behavior depends on
the contents of the plan baseline:
– If fixed plans exist in the plan baseline, then the optimizer uses the fixed plan
(see “Fixed Plans”) with the lowest cost.
– If no fixed plans exist in the plan baseline, then the optimizer uses the baseline
plan with the lowest cost.
– If no reproducible plans exist in the plan baseline, which could happen if every
plan in the baseline referred to a dropped index, then the optimizer uses the
newly generated cost-based plan.
The following graphic shows the decision tree for SQL plan selection.
SQL is issued
Generate execution
plan
No No
Compare costs of
accepted plans
Execute lowest-cost
plan in baseline
Plan Evolution
In general, SQL plan evolution is the process by which the optimizer verifies new
plans and adds them to an existing SQL plan baseline. Specifically, plan evolution
consists of the following distinct steps:
2. Adding unaccepted plans to the plan baseline as accepted plans after the database
has proved that they perform as well as accepted plans
In the standard case of plan evolution, the optimizer performs the preceding steps
sequentially, so that a new plan is not usable by SQL plan management until the
optimizer verifies plan performance relative to the SQL plan baseline. However, you
can configure SQL plan management to perform one step without performing the
other. The following graphic shows the possible paths for plan evolution:
Verifying Adding
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM package
• SQL profiles
• SQL patches
The SMB stores information that the optimizer can use to maintain or improve SQL
performance.
The SMB resides in the SYSAUX tablespace and uses automatic segment-space
management. Because the SMB is located entirely within the SYSAUX tablespace, the
database does not use SQL plan management and SQL tuning features when this
tablespace is unavailable.
The following graphic illustrates the SMB architecture.
SYSAUX
SQL SQL
Statement Profiles
Log
SQL SQL
Plan Patches
History
Note:
Data visibility and privilege requirements may differ when using the SMB
with pluggable databases. See Oracle Database Administrator's Guide for a table
that summarizes how manageability features work in a container database
(CDB).
See Also:
Oracle Database Administrator's Guide to learn about the SYSAUX tablespace
See Also:
System altered.
no rows selected
JOB_TITLE
-----------------------------------
President
SIGNATURE BATCH#
---------- ----------
1.8096E+19 1
Now the session executes a different jobs query. The log shows two tracked
statements:
SQL> SELECT job_title FROM hr.jobs WHERE job_id='PR_REP';
JOB_TITLE
-----------------------------------
Public Relations Representative
SIGNATURE BATCH#
---------- ----------
1.7971E+19 1
1.8096E+19 1
no rows selected
The session executes the query for job_id='PR_REP' a second time. Because this
statement is now repeatable, and because automatic SQL plan capture is enabled, the
database creates a plan baseline for this statement. The query for job_id='AD_PRES'
has only been executed once, so no plan baseline exists for it.
SQL> SELECT job_title FROM hr.jobs WHERE job_id='PR_REP';
JOB_TITLE
-----------------------------------
Public Relations Representative
SQL_HANDLE SQL_TEXT
-------------------- --------------------
SQL_f9676a330f972dd5 SELECT job_title FRO
M hr.jobs WHERE job_
id='PR_REP'
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE function
Enabled Plans
An enabled plan is eligible for use by the optimizer. The database automatically marks
all plans in the plan history as enabled even if they are still unaccepted. You can
manually change an enabled plan to a disabled plan, which means the optimizer can
no longer use the plan even if it is accepted.
Accepted Plans
A plan is accepted if and only if it is in the plan baseline. The plan history for a
statement contains all plans, both accepted and unaccepted. After the optimizer
generates the first accepted plan in a plan baseline, every subsequent unaccepted plan
is added to the plan history, awaiting verification, but is not in the SQL plan baseline.
Figure 23-1 shows plan histories for three different SQL statements. The SQL plan
baseline for one statement contains two accepted plans. The plan history for this
statement includes two unaccepted plans. A DBA has marked one unaccepted plan as
disabled so that the optimizer cannot use it.
GB
accepted
enabled
HJ
HJ
GB
accepted
enabled
HJ
HJ
Fixed Plans
A fixed plan is an accepted plan that is marked as preferred, so that the optimizer
considers only the fixed plans in the baseline. Fixed plans influence the plan selection
process of the optimizer.
Assume that three plans exist in the SQL plan baseline for a statement. You want the
optimizer to give preferential treatment to only two of the plans. As shown in Figure
23-2, you mark these two plans as fixed so that the optimizer uses only the best plan
from these two, ignoring the other plans.
GB fixed
accepted
DBA marks enabled
as fixed HJ Optimizer
HJ Considers
GB fixed
accepted
enabled
HJ
HJ
Ignores unless
fixed plans are
GB not reproducible
accepted
enabled
HJ
HJ
If new plans are added to a baseline that contains at least one enabled fixed plan, then
the optimizer cannot use the new plans until you manually declare them as fixed.
1. Access the Database Home page, as described in “Accessing the Database Home
Page in Cloud Control.”
2. From the Performance menu, select SQL, then SQL Plan Control.
The SQL Plan Control page appears.
3. Click Files to view the SQL Plan Baseline subpage, shown in Figure 23-3.
You can perform most SQL plan management tasks in this page or in pages
accessed through this page.
See Also:
DBMS_SPM Package
On the command line, use the DBMS_SPM and DBMS_XPLAN PL/SQL packages to
perform most SQL plan management tasks. Table 23-1 describes the most relevant
DBMS_SPM procedures and functions for creating, dropping, and loading SQL plan
baselines.
“About the DBMS_SPM Evolve Functions” describes the functions related to SQL plan
evolution.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM package
• Set initialization parameters to control whether the database captures and uses SQL
plan baselines, and whether it evolves new plans.
See “Configuring SQL Plan Management”.
Use PL/SQL to verify the performance of specified plans and add them to plan
baselines.
See “Evolving SQL Plan Baselines Manually”.
• OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=false
For any repeatable SQL statement that does not already exist in the plan history,
the database does not automatically create an initial SQL plan baseline for the
statement. See “Automatic Initial Plan Capture”.
• OPTIMIZER_USE_SQL_PLAN_BASELINES=true
For any SQL statement that has an existing SQL plan baseline, the database
automatically adds new plans to the SQL plan baseline as nonaccepted plans. See
“Plan Selection”.
Note:
The settings of the preceding parameters are independent of each other. For
example, if OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES is true, then the
database creates initial plan baselines for new statements even if
OPTIMIZER_USE_SQL_PLAN_BASELINES is false.
If the default behavior is what you intend, then skip this section.
The following sections explain how to change the default parameter settings from the
command line. If you use Cloud Control, then set these parameters in the SQL Plan
Baseline subpage (shown in Figure 23-3).
Caution:
When automatic baseline capture is enabled, the database creates a SQL plan
baseline for every repeatable statement, including all recursive SQL and
monitoring SQL. Thus, automatic capture may result in the creation of an
extremely large number of plan baselines.
1. Connect SQL*Plus to the database with the appropriate privileges, and then show
the current settings for SQL plan management.
For example, connect SQL*Plus to the database with administrator privileges and
execute the following command (sample output included):
SQL> SHOW PARAMETER SQL_PLAN
If the parameters are set as you intend, then skip the remaining steps.
1. Connect SQL*Plus to the database with the appropriate privileges, and then show
the current settings for SQL plan management.
For example, connect SQL*Plus to the database with administrator privileges and
execute the following command (sample output included):
SQL> SHOW PARAMETER SQL_PLAN
If the parameters are set as you intend, then skip the remaining steps.
See Also:
Oracle Database Reference to learn about the SQL plan baseline initialization
parameters
Assumptions
The tutorial in this section assumes the following:
• You want the task to time out after 1200 seconds per execution.
1. Connect SQL*Plus to the database with the appropriate privileges, and then
optionally query the current task settings.
For example, connect SQL*Plus to the database with administrator privileges and
execute the following query:
COL PARAMETER_NAME FORMAT a25
COL VALUE FORMAT a10
SELECT PARAMETER_NAME, PARAMETER_VALUE AS "VALUE"
FROM DBA_ADVISOR_PARAMETERS
WHERE ( (TASK_NAME = 'SYS_AUTO_SPM_EVOLVE_TASK') AND
( (PARAMETER_NAME = 'ACCEPT_PLANS') OR
(PARAMETER_NAME = 'TIME_LIMIT') ) );
For example, the following PL/SQL block sets a time limit to 20 minutes, and also
automatically accepts plans:
BEGIN
DBMS_SPM.SET_EVOLVE_TASK_PARAMETER(
task_name => 'SYS_AUTO_SPM_EVOLVE_TASK'
, parameter => 'LOCAL_TIME_LIMIT'
, value => 1200
);
DBMS_SPM.SET_EVOLVE_TASK_PARAMETER(
task_name => 'SYS_AUTO_SPM_EVOLVE_TASK'
, parameter => 'ACCEPT_PLANS'
, value => 'true'
);
END;
/
See Also:
Oracle Database PL/SQL Packages and Types Reference for complete reference
information for DBMS_SPM
sql_handle SQL handle of the statement. Retrieve the SQL handle by joining the
V$SQL.SQL_PLAN_BASELINE and DBA_SQL_PLAN_BASELINES
views on the PLAN_NAME columns.
This section explains how to show plans in a baseline from the command line. If you
use Cloud Control, then display plan baselines from the SQL Plan Baseline subpage
shown in Figure 23-3.
1. Connect SQL*Plus to the database with the appropriate privileges, and then
obtain the SQL ID of the query whose plan you want to display.
For example, assume that a SQL plan baseline exists for a SELECT statement with
the SQL ID 31d96zzzpcys9.
---------------------------------------------------------------------------
SQL handle: SQL_513f7f8a91177b1a
SQL text: select * from hr.employees where employee_id=100
---------------------------------------------------------------------------
---------------------------------------------------------------------------
Plan name: SQL_PLAN_52gvzja8jfysuc0e983c6 Plan id: 3236529094
Enabled: YES Fixed: NO Accepted: YES Origin: AUTO-CAPTURE
---------------------------------------------------------------------------
-----------------------------------------------------
| Id | Operation | Name |
-----------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES |
The results show that the plan for SQL ID 31d96zzzpcys is named
SQL_PLAN_52gvzja8jfysuc0e983c6 and was captured automatically.
See Also:
Note:
You can load plans from Automatic Workload Repository snapshots into an
STS, and then load plans from the STS into the SQL plan baseline.
• Staging table
Use the DBMS_SPM package to define a staging table,
DBMS_SPM.PACK_STGTAB_BASELINE to copy the baselines into a staging table,
and Oracle Data Pump to transfer the table to another database. On the destination
database, use DBMS_SPM.UNPACK_STGTAB_BASELINE to unpack the plans from
the staging table and put the baselines into the SMB.
A use case is the introduction of new SQL statements into the database from a new
application module. A vendor can ship application software with SQL plan
baselines for the new SQL. In this way, the new SQL uses plans that are known to
• Stored outline
Migrate stored outlines to SQL plan baselines. After the migration, you maintain
the same plan stability that you had using stored outlines while being able to use
the more advanced features provided by SQL Plan Management, such as plan
evolution. See “Migrating Stored Outlines to SQL Plan Baselines ”.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM.PACK_STGTAB_BASELINE Function
Function Description
Parameter
sqlset_name Name of the STS from which the plans are loaded into SQL plan
baselines.
basic_filter A filter applied to the STS to select only qualifying plans to be loaded.
The filter can take the form of any WHERE clause predicate that can be
specified against the view DBA_SQLSET_STATEMENTS.
fixed Default NO means the loaded plans are used as nonfixed plans. YES
means the loaded plans are fixed plans. “Plan Selection” explains that
the optimizer chooses a fixed plan in the plan baseline over a nonfixed
plan.
This section explains how to load plans from the command line. In Cloud Control, go
to the SQL Plan Baseline subpage (shown in Figure 23-3) and click Load to load plan
baselines from SQL tuning sets.
Assumptions
This tutorial assumes the following:
• You have loaded the plan from the shared SQL area into the SQL tuning set named
SPM_STS, which is owned by user SPM.
1. Connect SQL*Plus to the database with the appropriate privileges, and then verify
which plans are in the SQL tuning set.
For example, query DBA_SQLSET_STATEMENTS for the STS name (sample output
included):
SELECT SQL_TEXT
FROM DBA_SQLSET_STATEMENTS
WHERE SQLSET_NAME = 'SPM_STS';
SQL_TEXT
--------------------
SELECT /*LOAD_STS*/
*
FROM sh.sales
WHERE quantity_sold
> 40
ORDER BY prod_id
The output shows that the plan for the select /*LOAD_STS*/ statement is in
the STS.
2. Load the plan from the STS into the SQL plan baseline.
For example, in SQL*Plus execute the function as follows:
VARIABLE cnt NUMBER
EXECUTE :cnt := DBMS_SPM.LOAD_PLANS_FROM_SQLSET( -
sqlset_name => 'SPM_STS', -
basic_filter => 'sql_text like ''SELECT /*LOAD_STS*/%''' );
The basic_filter parameter specifies a WHERE clause that loads only the plans
for the queries of interest. The variable cnt stores the number of plans loaded
from the STS.
3. Query the data dictionary to ensure that the plan was loaded into the baseline for
the statement.
The following statement queries the DBA_SQL_PLAN_BASELINES view (sample
output included).
SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
2 ORIGIN, ENABLED, ACCEPTED
3 FROM DBA_SQL_PLAN_BASELINES;
The output shows that the plan is accepted, which means that it is in the plan
baseline. Also, the origin is MANUAL-LOAD, which means that the plan was loaded
by an end user rather than automatically captured.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM.LOAD_PLANS_FROM_SQLSET function
fixed Default NO means the loaded plans are used as nonfixed plans. YES
means the loaded plans are fixed plans (see “Fixed Plans”). “Plan
Selection” explains that the optimizer chooses a fixed plan in the plan
baseline over a nonfixed plan.
This section explains how to load plans using the command line. In Cloud Control, go
to the SQL Plan Baseline subpage (shown in Figure 23-3) and click Load to load plan
baselines from the shared SQL area.
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database with the appropriate privileges, and then
determine the SQL IDs of the relevant statements in the shared SQL area.
For example, query V$SQL for the SQL ID of the sh.sales query (sample output
included):
SELECT SQL_ID, CHILD_NUMBER AS "Child Num",
PLAN_HASH_VALUE AS "Plan Hash",
OPTIMIZER_ENV_HASH_VALUE AS "Opt Env Hash"
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT /*LOAD_CC*/%';
The preceding output shows that the SQL ID of the statement is 27m0sdw9snw59.
2. Load the plans for the specified statements into the SQL plan baseline.
For example, execute the LOAD_PLANS_FROM_CURSOR_CACHE function in
SQL*Plus to load the plan for the statement with the SQL ID 27m0sdw9snw59:
VARIABLE cnt NUMBER
EXECUTE :cnt := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE( -
sql_id => '27m0sdw9snw59');
In the preceding example, the variable cnt contains the number of plans that
were loaded.
3. Query the data dictionary to ensure that the plans were loaded into the baseline
for the statement.
The following statement queries DBA_SQL_PLAN_BASELINES (sample output
included):
SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
ORIGIN, ENABLED, ACCEPTED
FROM DBA_SQL_PLAN_BASELINES;
The output shows that the plan is accepted, which means that it is in the plan
baseline for the statement. Also, the origin is MANUAL-LOAD, which means that the
statement was loaded by an end user rather than automatically captured.
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn how to use the
DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE function
database and confirmed that they have performed well. You may then want to load
these plans into a production database.
A staging table is a table that, for the duration of its existence, stores plans so that the
plans do not disappear from the table while you are unpacking them. Use the
DBMS.CREATE_STGTAB_BASELINE procedure to create a staging table. To pack
(insert row into) and unpack (extract rows from) the staging table, use the
PACK_STGTAB_BASELINE and UNPACK_STGTAB_BASELINE functions of the
DBMS_SPM package. Oracle Data Pump Import and Export enable you to copy the
staging table to a different database.
The following graphic depicts the basic steps.
Pack 2
1 Unpack 6
1
SQL SQL
Management Management
Base Base
SQL Plan SQL Plan
Baselines Baselines
Assumptions
This tutorial assumes the following:
• You want to create a staging table named stage1 in the source database.
• You want to load all plans owned by user spm into the staging table.
1. Connect SQL*Plus to the source database with the appropriate privileges, and
then create a staging table using the CREATE_STGTAB_BASELINE procedure.
The following example creates a staging table named stage1:
BEGIN
DBMS_SPM.CREATE_STGTAB_BASELINE (
table_name => 'stage1');
END;
/
2. On the source database, pack the SQL plan baselines you want to export from the
SQL management base into the staging table.
The following example packs enabled plan baselines created by user spm into
staging table stage1. Select SQL plan baselines using the plan name
(plan_name), SQL handle (sql_handle), or any other plan criteria. The
table_name parameter is mandatory.
DECLARE
my_plans number;
BEGIN
my_plans := DBMS_SPM.PACK_STGTAB_BASELINE (
table_name => 'stage1'
, enabled => 'yes'
, creator => 'spm'
);
END;
/
3. Export the staging table stage1 into a dump file using Oracle Data Pump Export.
5. On the destination database, import the staging table stage1 from the dump file
using the Oracle Data Pump Import utility.
6. On the destination database, unpack the SQL plan baselines from the staging table
into the SQL management base.
The following example unpacks all fixed plan baselines stored in the staging table
stage1:
DECLARE
my_plans NUMBER;
BEGIN
my_plans := DBMS_SPM.UNPACK_STGTAB_BASELINE (
table_name => 'stage1'
, fixed => 'yes'
);
END;
/
See Also:
• Oracle Database PL/SQL Packages and Types Reference for more information
about using the DBMS_SPM package
• Oracle Database Utilities for detailed information about using the Data
Pump Export and Import utilities
Table 23-5 DBMS_SPM Functions and Procedures for Managing Plan Evolution
Tasks
Oracle recommends that you configure SPM Evolve Advisor to run automatically (see
“Configuring the Automatic SPM Evolve Advisor Task”). You can also evolve SQL
plan baselines manually. Figure 23-4 shows the basic workflow for managing SQL
plan management tasks.
DBMS_SPM.CREATE_EVOLVE_TASK
DBMS_SPM.SET_EVOLVE_TASK_PARAMETER
DBMS_SPM.EXECUTE_EVOLVE_TASK
DBMS_SPM.IMPLEMENT_EVOLVE_TASK
DBMS_SPM.REPORT_EVOLVE_TASK
Typically, you manage SQL plan evolution tasks in the following sequence:
See Also:
Oracle Database PL/SQL Packages and Types Reference for information about the
DBMS_SPM package
Function Description
Parameter
sql_handle SQL handle of the statement. The default NULL considers all SQL
statements with unaccepted plans.
plan_name Plan identifier. The default NULL means consider all unaccepted plans of
the specified SQL handle or all SQL statements if the SQL handle is NULL.
Function Description
Parameter
time_limit Time limit in number of minutes. The time limit for first unaccepted plan
equals the input value. The time limit for the second unaccepted plan
equals the input value minus the time spent in first plan verification, and
so on. The default DBMS_SPM.AUTO_LIMIT means let the system choose
an appropriate time limit based on the number of plan verifications
required to be done.
This section explains how to evolve plan baselines from the command line. In Cloud
Control, from the SQL Plan Baseline subpage (shown in Figure 23-3), select a plan, and
then click Evolve.
Assumptions
This tutorial assumes the following:
• You do not have the automatic evolve task enabled (see “Managing the SPM
Evolve Advisor Task”).
• You want to create a SQL plan baseline for the following query:
SELECT /* q1_group_by */ prod_name, sum(quantity_sold)
FROM products p, sales s
WHERE p.prod_id = s.prod_id
AND p.prod_category_id =203
GROUP BY prod_name;
• You want to create two indexes to improve the query performance, and then evolve
the plan that uses these indexes if it performs better than the plan currently in the
plan baseline.
c. Connect to the database as user sh, and then set SQL*Plus display
parameters:
CONNECT sh
-- enter password
SET PAGES 10000 LINES 140
SET SERVEROUTPUT ON
COL SQL_TEXT FORMAT A20
COL SQL_HANDLE FORMAT A20
COL PLAN_NAME FORMAT A30
COL ORIGIN FORMAT A12
SET LONGC 60535
SET LONG 60535
SET ECHO ON
2. Execute the SELECT statements so that SQL plan management captures them:
b. Query the data dictionary to confirm that no plans exist in the plan baseline.
For example, execute the following query (sample output included):
SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED,
ACCEPTED, FIXED, AUTOPURGE
FROM DBA_SQL_PLAN_BASELINES
WHERE SQL_TEXT LIKE '%q1_group%';
no rows selected
3. Query the data dictionary to ensure that the plans were loaded into the plan
baseline for the statement.
Example 23-2 executes the following query (sample output included).
The output shows that the plan is accepted, which means that it is in the plan
baseline for the statement. Also, the origin is AUTO-CAPTURE, which means that
the statement was automatically captured and not manually loaded.
4. Explain the plan for the statement and verify that the optimizer is using this plan.
For example, explain the plan as follows, and then display it:
EXPLAIN PLAN FOR
SELECT /* q1_group_by */ prod_name, sum(quantity_sold)
FROM products p, sales s
WHERE p.prod_id = s.prod_id
AND p.prod_category_id =203
GROUP BY prod_name;
------------------------------------------
| Id | Operation | Name |
------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | HASH GROUP BY | |
| 2 | HASH JOIN | |
| 3 | TABLE ACCESS FULL | PRODUCTS |
| 4 | PARTITION RANGE ALL| |
| 5 | TABLE ACCESS FULL | SALES |
------------------------------------------
Note
-----
- SQL plan baseline "SQL_PLAN_0gwbcfvzskcu242949306" used for this statement
The note indicates that the optimizer is using the plan shown with the plan name
listed in Example 23-2.
7. Query the data dictionary to ensure that the plan was loaded into the SQL plan
baseline for the statement.
Example 23-3 executes the following query (sample output included).
The output shows that the new plan is unaccepted, which means that it is in the
statement history but not the SQL plan baseline.
8. Explain the plan for the statement and verify that the optimizer is using the
original nonindexed plan.
For example, explain the plan as follows, and then display it:
EXPLAIN PLAN FOR
SELECT /* q1_group_by */ prod_name, sum(quantity_sold)
FROM products p, sales s
WHERE p.prod_id = s.prod_id
AND p.prod_category_id =203
GROUP BY prod_name;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null, null, 'basic +note'));
------------------------------------------
| Id | Operation | Name |
------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | HASH GROUP BY | |
| 2 | HASH JOIN | |
| 3 | TABLE ACCESS FULL | PRODUCTS |
| 4 | PARTITION RANGE ALL| |
| 5 | TABLE ACCESS FULL | SALES |
------------------------------------------
Note
-----
- SQL plan baseline "SQL_PLAN_0gwbcfvzskcu242949306" used for this statement
The note indicates that the optimizer is using the plan shown with the plan name
listed in Example 23-2.
9. Connect as an administrator, and then create an evolve task that considers all SQL
statements with unaccepted plans.
For example, execute the DBMS_SPM.CREATE_EVOLVE_TASK function and then
obtain the name of the task:
CONNECT / AS SYSDBA
VARIABLE cnt NUMBER
VARIABLE tk_name VARCHAR2(50)
VARIABLE exe_name VARCHAR2(50)
VARIABLE evol_out CLOB
Now that the task has been created and has a unique name, execute the task.
:EXE_NAME
---------------------------------------------------------------------------
EXEC_1
Task Information:
---------------------------------------------
Task Name : TASK_11
Task Owner : SYS
Execution Name : EXEC_1
SUMMARY SECTION
---------------------------------------------------------------------------
Number of plans processed : 1
Number of findings : 1
Number of recommendations : 1
Number of errors : 0
---------------------------------------------------------------------------
DETAILS SECTION
---------------------------------------------------------------------------
Object ID : 2
Test Plan Name : SQL_PLAN_0gwbcfvzskcu20135fd6c
Base Plan Name : SQL_PLAN_0gwbcfvzskcu242949306
SQL Handle : SQL_07f16c76ff893342
Parsing Schema : SH
Test Plan Creator : SH
SQL Text : SELECT /*q1_group_by*/ prod_name,
sum(quantity_sold)
FROM products p, sales s
WHERE p.prod_id=s.prod_id AND p.prod_category_id=203
GROUP BY prod_name
Execution Statistics:
-----------------------------
Base Plan Test Plan
---------------------------- ------------------------
Elapsed Time (s): .044336 .012649
CPU Time (s): .044003 .012445
Buffer Gets: 360 99
Optimizer Cost: 924 891
Disk Reads: 341 82
Direct Writes: 0 0
Rows Processed: 4 2
Executions: 5 9
FINDINGS SECTION
---------------------------------------------------------------------------
Findings (1):
-----------------------------
1. The plan was verified in 2.18 seconds. It passed the benefit criterion
because its verified performance was 2.01 times better than that of the
baseline plan.
Recommendation:
-----------------------------
Consider accepting the plan. Execute
dbms_spm.accept_sql_plan_baseline(task_name => 'TASK_11', object_id => 2,
task_owner => 'SYS');
Baseline Plan
-----------------------------
Plan Id : 1
Plan Hash Value : 1117033222
---------------------------------------------------------------------------
| Id| Operation | Name | Rows | Bytes |Cost | Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 21 | 861 | 924 | 00:00:12|
| 1 | HASH GROUP BY | | 21 | 861 | 924 | 00:00:12|
| *2| HASH JOIN | |267996|10987836 | 742 | 00:00:09|
| *3| TABLE ACCESS FULL | PRODUCTS | 21 | 714 | 2 | 00:00:01|
| 4 | PARTITION RANGE ALL | |918843| 6431901 | 662 | 00:00:08|
| 5 | TABLE ACCESS FULL | SALES |918843| 6431901 | 662 | 00:00:08|
---------------------------------------------------------------------------
Test Plan
-----------------------------
Plan Id : 2
Plan Hash Value : 20315500
---------------------------------------------------------------------------
|Id| Operation | Name | Rows | Bytes | Cost| Time |
---------------------------------------------------------------------------
| 0|SELECT STATEMENT | | 21| 861|891|00:00:11|
| 1| SORT GROUP BY NOSORT| | 21| 861|891|00:00:11|
| 2| NESTED LOOPS | |267996|10987836|891|00:00:11|
|*3| INDEX RANGE SCAN |IND_PROD_CAT_NAME | 21| 714| 1|00:00:01|
|*4| INDEX RANGE SCAN |IND_SALES_PROD_QTY| 12762| 89334| 42|00:00:01|
---------------------------------------------------------------------------
This report indicates that the new execution plan, which uses the two new
indexes, performs better than the original plan.
13. Query the data dictionary to ensure that the new plan is accepted.
Example 23-3 executes the following query (sample output included).
The output shows that the new plan is accepted.
See Also:
Oracle Database PL/SQL Packages and Types Reference for information about
using the DBMS_SPM evolve functions
quantity_sold)
FROM products p, s
ales s
WHERE p.prod_id = s
.prod_id
AND p.prod_catego
ry_id =203
GROUP BY prod_name
Function Description
Parameter
plan_name Name of a specific plan. Default NULL drops all plans associated with
the SQL statement identified by sql_handle.
This section explains how to drop baselines from the command line. In Cloud Control,
from the SQL Plan Baseline subpage (shown in Figure 23-3), select a plan, and then
click Drop.
Assumptions
This tutorial assumes that you want to drop all plans for the following SQL statement,
effectively dropping the SQL plan baseline:
SELECT /* repeatable_sql */ COUNT(*) FROM hr.jobs;
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the data dictionary for the plan baseline.
Example 23-5 executes the following query (sample output included).
no rows selected
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DROP_SQL_PLAN_BASELINE function
Parameter Description
Assumptions
This tutorial assumes the following:
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the data dictionary to see the current space budget percent.
For example, execute the following query (sample output included):
SELECT PARAMETER_NAME, PARAMETER_VALUE AS "%_LIMIT",
( SELECT sum(bytes/1024/1024) FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = 'SYSAUX' ) AS SYSAUX_SIZE_IN_MB,
PARAMETER_VALUE/100 *
( SELECT sum(bytes/1024/1024) FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = 'SYSAUX' ) AS "CURRENT_LIMIT_IN_MB"
FROM DBA_SQL_MANAGEMENT_CONFIG
WHERE PARAMETER_NAME = 'SPACE_BUDGET_PERCENT';
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
CONFIGURE function
1. Connect SQL*Plus to the database with the appropriate privileges, and then query
the data dictionary to see the current plan retention period.
For example, execute the following query (sample output included):
SQL> SELECT PARAMETER_NAME, PARAMETER_VALUE
2 FROM DBA_SQL_MANAGEMENT_CONFIG
3 WHERE PARAMETER_NAME = 'PLAN_RETENTION_WEEKS';
PARAMETER_NAME PARAMETER_VALUE
------------------------------ ---------------
PLAN_RETENTION_WEEKS 53
PARAMETER_NAME PARAMETER_VALUE
------------------------------ ---------------
PLAN_RETENTION_WEEKS 105
See Also:
Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM.CONFIGURE procedure
This chapter explains the concepts and tasks relating to stored outline migration. This
chapter contains the following topics:
Note:
Starting in Oracle Database 12c, stored outlines are deprecated. See Migrating
Stored Outlines to SQL Plan Baselines for an alternative.
while being able to use the more advanced features provided by the SQL Plan
Management framework.
Specifically, the section explains how to address the following problems:
• Hints in a stored outline can become invalid, as with an index hint on a dropped
index. In such cases, the database still uses the outlines but excludes the invalid
hints, producing a plan that is often worse than the original plan or the current
best-cost plan generated by the optimizer.
• For a SQL statement, the optimizer can only choose the plan defined in the stored
outline in the currently specified category. The optimizer cannot choose from other
stored outlines in different categories or the current cost-based plan even if they
improve performance.
• Stored outlines are a reactive tuning technique, which means that you only use a
stored outline to address a performance problem after it has occurred. For example,
you may implement a stored outline to correct the plan of a SQL statement that
became high-load. In this case, you used stored outlines instead of proactively
tuning the statement before it became high-load.
The stored outline migration PL/SQL API helps solve the preceding problems in the
following ways:
• SQL plan baselines enable the optimizer to use the same optimal plan and allow
this plan to evolve over time.
For a specified SQL statement, you can add new plans as SQL plan baselines after
they are verified not to cause performance regressions.
• For a specific SQL statement, the database can maintain multiple plan baselines.
The optimizer can choose from a set of optimal plans for a specific SQL statement
instead of being restricted to a single plan per category, as required by stored
outlines.
a. The database copies information in the outline needed by the plan baseline.
The database copies it directly or calculates it based on information in the
outline. For example, the text of the SQL statement exists in both schemas, so
the database can copy the text from outline to baseline.
b. The database reparses the hints to obtain information not in the outline.
The plan hash value and plan cost cannot be derived from the existing
information in the outline, which necessitates reparsing the hints.
3. The database obtains missing information when it chooses the SQL plan baseline
for the first time to execute the SQL statement.
The compilation environment and execution statistics are only available during
execution when the plan baseline is parsed and compiled.
The migration is complete only after the preceding phases complete.
When migrating stored outlines to SQL plan baselines, Oracle Database maps every
outline category to a SQL plan baseline module with the same name. As shown in the
following diagram, the outline category OLTP is mapped to the baseline module OLTP.
After migration, DEFAULT is a super-category that contains all SQL plan baselines.
Category DEFAULT
SELECT...
Category DW Module DW
SELECT...
ALTER_SQL_PLAN_BASELINE Changes an attribute of a single plan or all plans associated with a SQL
statement.
DROP_MIGRATED_STORED_OUTLINE Drops stored outlines that have been migrated to SQL plan baselines.
The function finds stored outlines marked as MIGRATED in the
DBA_OUTLINES view, and then drops these outlines from the database.
You can control stored outline and plan baseline behavior with initialization and
session parameters. Table 24-3 describes the relevant parameters. See Table 24-5 and
Table 24-6 for an explanation of how these parameter settings interact.
You can use database views to access information relating to stored outline migration.
Table 24-4 describes the following main views.
View Description
DBA_OUTLINES Describes all stored outlines in the database.
The MIGRATED column is important for outline migration
and shows one of the following values: NOT-MIGRATED
and MIGRATED. When MIGRATED, the stored outline has
been migrated to a plan baseline and is not usable.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM package
3. Determine which stored outlines meet the following prerequisites for migration
eligibility:
5. Decide whether the stored outlines migrated to SQL plan baselines use fixed
plans or nonfixed plans:
• Fixed plans
A fixed plan is frozen. If a fixed plan is reproducible using the hints stored in
plan baseline, then the optimizer always chooses the lowest-cost fixed plan
baseline over plan baselines that are not fixed. Essentially, a fixed plan baseline
acts as a stored outline with valid hints.
A fixed plan is reproducible when the database can parse the statement based
on the hints stored in the plan baseline and create a plan with the same plan
hash value as the one in the plan baseline. If one of more of the hints become
invalid, then the database may not be able to create a plan with the same plan
hash value. In this case, the plan is nonreproducible.
If a fixed plan cannot be reproduced when parsed using its hints, then the
optimizer chooses a different plan, which can be either of the following:
• Nonfixed plans
If a plan baseline does not contain fixed plans, then SQL Plan Management
considers the plans equally when picking a plan for a SQL statement.
6. Before beginning the actual migration, ensure that the Oracle database meets the
following prerequisites:
See Also:
• To allow SQL Plan Management to select from all plans in a plan baseline for a SQL
statement instead of applying the same fixed plan after migration
• To allow the SQL plan baseline to evolve in the face of database changes by adding
new plans to the baseline
Assumptions
This tutorial assumes the following:
• You want the module names of the baselines to be identical to the category names
of the migrated outlines.
The following sample PL/SQL block migrates all stored outlines to fixed
baselines:
DECLARE
my_report CLOB;
BEGIN
my_outlines := DBMS_SPM.MIGRATE_STORED_OUTLINE(
attribute_name => 'all' );
END;
/
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM package
• Oracle Database SQL Language Reference to learn about the ALTER SYSTEM
statement
Assumptions
This tutorial assumes the following:
• You want to migrate only the stored outlines in the category named firstrow.
See Oracle Database PL/SQL Packages and Types Reference for syntax and semantics of
the DBMS_SPM.MIGRATE_STORED_OUTLINE function.
• You want the module names of the baselines to be identical to the category names
of the migrated outlines.
After migration, the SQL plan baselines is in module firstrow and category
DEFAULT.
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM package
• Oracle Database SQL Language Reference to learn about the ALTER SYSTEM
statement
• To configure the database to use plan baselines instead of stored outlines for stored
outlines that have been migrated to SQL plan baselines
• To create SQL plan baselines instead of stored outlines for future SQL statements
• To drop the stored outlines that have been migrated to SQL plan baselines
This section explains how to set initialization parameters relating to stored outlines
and plan baselines. The OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES and
CREATE_STORED_OUTLINES initialization parameters determine how and when the
database creates stored outlines and SQL plan baselines. Table 24-5 explains the
interaction between these parameters.
Table 24-6 (Cont.) Use of Stored Outlines and SQL Plan Baselines
Assumptions
This tutorial assumes the following:
• You have completed the basic steps in the stored outline migration (see “Basic
Steps in Stored Outline Migration”).
• Some stored outlines may have been created before Oracle Database 10g.
Hints in releases before Oracle Database 10g use a local hint format. After
migration, hints stored in a plan baseline use the global hints format introduced in
Oracle Database 10g.
1. Connect SQL*Plus to the database with the appropriate privileges, and then check
that SQL plan baselines have been created as the result of migration.
Ensure that the plans are enabled and accepted. For example, enter the following
query (partial sample output included):
SELECT SQL_HANDLE, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED, FIXED, MODULE
FROM DBA_SQL_PLAN_BASELINES;
4. Drop all stored outlines that have been migrated to SQL plan baselines.
For example, the following statements drops all stored outlines with status
MIGRATED in DBA_OUTLINES:
DECLARE
v_cnt PLS_INTEGER;
BEGIN
v_cnt := DBMS_SPM.DROP_MIGRATED_STORED_OUTLINE();
DBMS_OUTPUT.PUT_LINE('Migrated stored outlines dropped: ' || v_cnt);
END;
/
• When executing a SQL statement, the database creates plan baselines but does
not create stored outlines.
• The database only uses stored outlines when the equivalent SQL plan baselines
do not exist.
For example, the following SQL statements instruct the database to create SQL
plan baselines instead of stored outlines when a SQL statement is executed. The
example also instructs the database to apply a stored outline in category allrows
or DEFAULT only if it exists and has not been migrated to a SQL plan baseline. In
other cases, the database applies SQL plan baselines instead.
ALTER SYSTEM
SET CREATE_STORED_OUTLINE = false SCOPE = BOTH;
ALTER SYSTEM
SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES = true SCOPE = BOTH;
ALTER SYSTEM
SET OPTIMIZER_USE_SQL_PLAN_BASELINES = true SCOPE = BOTH;
ALTER SESSION
SET USE_STORED_OUTLINES = allrows SCOPE = BOTH;
See Also:
• Oracle Database PL/SQL Packages and Types Reference to learn about the
DBMS_SPM package
This appendix provides an overview of data access methods using indexes and
clusters that can enhance or degrade performance.
The appendix contains the following topics:
table, regardless of whether queries use them. Index maintenance can present a
significant CPU and I/O resource demand in any write-intensive application. In other
words, do not build indexes unless necessary.
To maintain optimal performance, drop indexes that an application is not using. You
can find indexes that are not being used by using the ALTER INDEX MONITORING
USAGE functionality over a period that is representative of your workload. This
monitoring feature records whether an index has been used. If you find that an index
has not been used, then drop it. Make sure you are monitoring a representative
workload to avoid dropping an index which is used, but not by the workload you
sampled.
Also, indexes within an application sometimes have uses that are not immediately
apparent from a survey of statement execution plans. An example of this is a foreign
key index on a parent table, which prevents share locks from being taken out on a
child table.
If you are deciding whether to create new indexes to tune statements, then you can
also use the EXPLAIN PLAN statement to determine whether the optimizer chooses to
use these indexes when the application is run. If you create new indexes to tune a
statement that is currently parsed, then Oracle Database invalidates the statement.
When the statement is next parsed, the optimizer automatically chooses a new
execution plan that could potentially use the new index. If you create new indexes on
a remote database to tune a distributed statement, then the optimizer considers these
indexes when the statement is next parsed.
Creating an index to tune one statement can affect the optimizer's choice of execution
plans for other statements. For example, if you create an index to be used by one
statement, then the optimizer can choose to use that index for other statements in the
application as well. For this reason, reexamine the application's performance and
execution plans, and rerun the SQL trace facility after you have tuned those statements
that you initially identified for tuning.
See Also:
• Oracle Database SQL Language Reference for syntax and semantics of the
ALTER INDEX MONITORING USAGE statement
See Also:
• Choose index keys that are highly selective. The selectivity of an index is the
percentage of rows in a table having the same value for the indexed key. An index
selectivity is optimal if few rows have the same value.
Note:
Indexing low selectivity columns can be helpful when the data distribution is
skewed so that one or two values occur much less often than other values.
• Do not use standard B-tree indexes on keys or expressions with few distinct values.
Such keys or expressions are usually unselective and therefore do not optimize
performance unless the frequently selected key values appear less frequently than
the other key values. You can use bitmap indexes effectively in such cases, unless
the index is modified frequently, as in a high concurrency OLTP application.
• Do not index keys that appear only in WHERE clauses with functions or operators. A
WHERE clause that uses a function, other than MIN or MAX, or an operator with an
indexed key does not make available the access path that uses the index except
with function-based indexes.
• When choosing to index a key, consider whether the performance gain for queries
is worth the performance loss for INSERTs, UPDATEs, and DELETEs and the use of
the space required to store the index. You might want to experiment by comparing
the processing times of the SQL statements with and without indexes. You can
measure processing time with the SQL trace facility.
See Also:
Oracle Database Development Guide for more information about the effects of
foreign keys on locking
• Improved selectivity
Sometimes you can combine two or more columns or expressions, each with low
selectivity, to form a composite index with higher selectivity.
• Reduced I/O
If all columns selected by a query are in a composite index, then Oracle Database
can return these values from the index without accessing the table.
A SQL statement can use an access path involving a composite index when the
statement contains constructs that use a leading portion of the index.
Note:
This is no longer the case with index skip scans. See “Index Skip Scans”.
A leading portion of an index is a set of one or more columns that were specified first
and consecutively in the list of columns in the CREATE INDEX statement that created
the index. Consider this CREATE INDEX statement:
CREATE INDEX comp_ind
ON table1(x, y, z);
• x, xy, and xyz combinations of columns are leading portions of the index
• yz, y, and z combinations of columns are not leading portions of the index
• If several queries select the same set of keys based on one or more key values, then
consider creating a composite index containing all of these keys.
Of course, consider the guidelines associated with the general performance
advantages and trade-offs of indexes described in the previous sections.
• Create the index so the keys used in WHERE clauses comprise a leading portion.
• If some keys appear in WHERE clauses more frequently, then create the index so that
the more frequently selected keys comprise a leading portion to allow the
statements that use only these keys to use the index.
• If all keys appear in WHERE clauses equally often but the data is physically ordered
on one of the keys, then place this key first in the composite index.
• Use the NO_INDEX hint to give the query optimizer maximum flexibility while
disallowing the use of a certain index.
• Use the FULL hint to instruct the optimizer to choose a full table scan instead of an
index scan.
• Use the INDEX or INDEX_COMBINE hints to instruct the optimizer to use one index
or a set of listed indexes instead of another.
Parallel execution uses indexes effectively. It does not perform parallel index range
scans, but it does perform parallel index lookups for parallel nested loops join
execution. If an index is very selective (few rows correspond to each index entry), then
a sequential index lookup might be better than a parallel table scan.
See Also:
Influencing the Optimizer for more information about the NO_INDEX, FULL,
INDEX, and INDEX_COMBINE and hints
could actually be larger than the table. In this case, it is faster to use the base table
rather than the index to re-create the index.
To reorganize or compact an existing index or to change its storage characteristics, use
the ALTER INDEX . . . REBUILD statement. The REBUILD statement uses the
existing index as the basis for the new one. All index storage statements are supported,
such as STORAGE (for extent allocation), TABLESPACE (to move the index to a new
tablespace), and INITRANS (to change the initial number of entries).
Usually, ALTER INDEX . . . REBUILD is faster than dropping and re-creating an
index, because this statement uses the fast full scan feature. It reads all the index
blocks using multiblock I/O, then discards the branch blocks. A further advantage of
this approach is that the old index is still available for queries while the rebuild is in
progress.
See Also:
Oracle Database SQL Language Reference for more information about the
CREATE INDEX and ALTER INDEX statements and restrictions on rebuilding
indexes
See Also:
is not checked. By placing a constraint in the enabled novalidated state, you enable the
constraint without locking the table.
If you change a constraint from disabled to enabled, then the table must be locked. No
new DML, queries, or DDL can occur, because no mechanism can ensure that
operations on the table conform to the constraint during the enable operation. The
enabled novalidated state prevents users from performing operations on the table that
violate the constraint.
The database can validate an enabled novalidated constraint with a parallel,
consistent-read query of the table to determine whether any data violates the
constraint. The database performs no locking, so the enable operation does not block
readers or writers. In addition, the database can validate enabled novalidated
constraints in parallel. The database can validate multiple constraints at the same time
and check the validity of each constraint using parallel query.
Note:
4. Enable novalidate all constraints. Do this to primary keys before foreign keys.
6. With a separate ALTER TABLE statement for each constraint, validate all
constraints. Do this to primary keys before foreign keys. For example,
CREATE TABLE t (a NUMBER CONSTRAINT apk PRIMARY KEY DISABLE,
b NUMBER NOT NULL);
CREATE TABLE x (c NUMBER CONSTRAINT afk REFERENCES t DISABLE);
At this point, users can start performing INSERT, UPDATE, DELETE, and SELECT
operations on table t.
ALTER TABLE t ENABLE CONSTRAINT apk;
ALTER TABLE x ENABLE CONSTRAINT afk;
See Also:
See Also:
• Oracle Database SQL Language Reference for more information about the
CREATE INDEX statement
contention for index pages, buffers, latches for update, and additional index
maintenance activity, which results in performance degradation.
With hash partitioned global indexes index entries are hashed to different partitions
based on partitioning key and the number of partitions. This spreads out contention
over number of defined partitions, resulting in increased throughput. Hash-
partitioned global indexes would benefit TPC-H refresh functions that are executed as
massive PDMLs into huge fact tables because contention for buffer latches would be
spread out over multiple partitions.
With hash partitioning, an index entry is mapped to a particular index partition based
on the hash value generated by Oracle Database. The syntax to create hash-partitioned
global index is very similar to hash-partitioned table. Queries involving equality and
IN predicates on index partitioning key can efficiently use global hash partitioned
index to answer queries quickly.
See Also:
Oracle Database Concepts and Oracle Database Administrator's Guide for more
information about global indexes tables
See Also:
Oracle Database Concepts and Oracle Database Administrator's Guide for more
information about index-organized tables
• The bitmap indexes used in the queries have been created on some or all of these
low- or medium-cardinality columns.
See Also:
Oracle Database Concepts and Oracle Database Data Warehousing Guide for more
information about bitmap indexing
See Also:
Oracle Database Data Warehousing Guide for examples and restrictions of bitmap
join indexes
The cartridge determines the parameters you can specify in creating and maintaining
the domain index. Similarly, the performance and storage characteristics of the
domain index are presented in the specific cartridge documentation.
Refer to the appropriate cartridge documentation for information such as the
following:
Note:
You can also create index types with the CREATE INDEXTYPE statement.
See Also:
Oracle Spatial and Graph Developer's Guide for information about the
SpatialIndextype
• In master-detail tables, the application often selects a master record and then the
corresponding detail records.
Detail records are stored in the same data blocks as the master record, so they are
likely still to be in memory when you select them, requiring Oracle Database to
perform less I/O.
• The application often selects many detail records of the same master.
In this case, consider storing a detail table alone in a cluster. This measure
improves the performance of queries that select detail records of the same master,
but does not decrease the performance of a full table scan on the master table. An
alternative is to use an index organized table.
Avoid clustering tables in the following circumstances:
• The application joins the tables only occasionally or modifies their common column
values frequently.
Modifying a row's cluster key value takes longer than modifying the value in an
nonclustered table, because Oracle Database might need to migrate the modified
row to another block to maintain the cluster.
• The application often performs full table scans of only one of the tables.
A full table scan of a clustered table can take longer than a full table scan of an
nonclustered table. Oracle Database is likely to read more blocks because the tables
are stored together.
• The data from all tables with the same cluster key value exceeds more than one or
two data blocks.
To access a row in a clustered table, Oracle Database reads all blocks containing
rows with that value. If these rows take up multiple blocks, then accessing a single
row could require more reads than accessing the same row in a nonclustered table.
• The number of rows for each cluster key value varies significantly.
This causes waste of space for the low cardinality key value. It causes collisions for
the high cardinality key values. Collisions degrade performance.
Consider the benefits and drawbacks of clusters for the application. For example, you
might decide that the performance gain for join statements outweighs the performance
loss for statements that modify cluster key values. You might want to experiment and
compare processing times with the tables both clustered and stored separately.
See Also:
• Use hash clusters to store tables accessed frequently by SQL statements with
WHERE clauses, if the WHERE clauses contain equality conditions that use the same
column or combination of columns. Designate this column or combination of
columns as the cluster key.
• Store a table in a hash cluster if you can determine how much space is required to
hold all rows with a given cluster key value, including rows to be inserted
immediately and rows to be inserted in the future.
• Use sorted hash clusters, where rows corresponding to each value of the hash
function are sorted on a specific columns in ascending order, when the database
can improve response time on operations with this sorted clustered data.
– You must allocate a great deal of space to the hash cluster in anticipation of the
table growing.
Full table scans must read all blocks allocated to the hash cluster, even though
some blocks might contain few rows. Storing the table alone reduces the number of
blocks read by full table scans.
• Do not store a table in a hash cluster if the application frequently modifies the
cluster key values. Modifying a row's cluster key value can take longer than
modifying the value in an nonclustered table, because Oracle Database might need
to migrate the modified row to another block to maintain the cluster.
If hashing is appropriate for the table based on the considerations in this list, then
storing a single table in a hash cluster can be useful. This is true regardless of whether
the table is joined frequently with other tables.
See Also:
accepted plan
In the context of SQL plan management, a plan that is in a SQL plan baseline for a
SQL statement and thus available for use by the optimizer. An accepted plan contains
a set of hints, a plan hash value, and other plan-related information.
access path
The means by which the database retrieves data from a database. For example, a query
using an index and a query using a full table scan use different access paths.
adaptive optimizer
A feature of the optimizer that enables it to adapt plans based on run-time statistics.
adaptive plan
An execution plan that changes after optimization because run-time conditions
indicate that optimizer estimates are inaccurate. An adaptive plan has different built-
in plan options. During the first execution, before a specific subplan becomes active,
the optimizer makes a a final decision about which option to use. The optimizer bases
its choice on observations made during the execution up to this point. Thus, an
adaptive plan enables the final plan for a statement to differ from the default plan.
ADDM
See Automatic Database Diagnostic Monitor (ADDM).
Glossary-1
antijoin
antijoin
A join that returns rows that fail to match the subquery on the right side. For example,
an antijoin can list departments with no employees. Antijoins use the NOT EXISTS or
NOT IN constructs.
automatic reoptimization
The ability of the optimizer to automatically change a plan on subsequent executions
of a SQL statement. Automatic reoptimization can fix any suboptimal plan chosen due
to incorrect optimizer estimates, from a suboptimal distribution method to an
incorrect choice of degree of parallelism.
Glossary-2
bitmap join index
AWR
See Automatic Workload Repository (AWR).
AWR snapshot
A set of data for a specific time that is used for performance comparisons. The delta
values captured by the snapshot represent the changes for each statistic over the time
period. Statistics gathered by are queried from memory. You can display the gathered
data in both reports and views.
baseline
In the context of AWR, the interval between two AWR snapshots that represent the
database operating at an optimal level.
bind-aware cursor
A bind-sensitive cursor that is eligible to use different plans for different bind values.
After a cursor has been made bind-aware, the optimizer chooses plans for future
executions based on the bind value and its cardinality estimate.
bind-sensitive cursor
A cursor whose optimal plan may depend on the value of a bind variable. The
database monitors the behavior of a bind-sensitive cursor that uses different bind
values to determine whether a different plan is beneficial.
bind variable
A placeholder in a SQL statement that must be replaced with a valid value or value
address for the statement to execute successfully. By using bind variables, you can
write a SQL statement that accepts inputs or parameters at run time. The following
query uses v_empid as a bind variable:
SELECT * FROM employees WHERE employee_id = :v_empid;
Glossary-3
bitmap piece
bitmap piece
A subcomponent of a single bitmap index entry. Each indexed column value may have
one or more bitmap pieces. The database uses bitmap pieces to break up an index
entry that is large in relation to the size of a block.
B-tree index
An index organized like an upside-down tree. A B-tree index has two types of blocks:
branch blocks for searching and leaf blocks that store values. The leaf blocks contain
every indexed data value and a corresponding rowid used to locate the actual row.
The "B" stands for "balanced" because all leaf blocks automatically stay at the same
depth.
bulk load
A CREATE TABLE AS SELECT or INSERT INTO ... SELECT operation.
cardinality
The number of rows that is expected to be or actually is returned by an operation in an
execution plan. Data has low cardinality when the number of distinct values in a
column is low in relation to the total number of rows.
Cartesian join
A join in which one or more of the tables does not have any join conditions to any
other tables in the statement. The optimizer joins every row from one data source with
every row from the other data source, creating the Cartesian product of the two sets.
child cursor
The cursor containing the plan, compilation environment, and other information for a
statement whose text is stored in a parent cursor. The parent cursor is number 0, the
first child is number 1, and so on. Child cursors reference the same SQL text as the
parent cursor, but are different. For example, two queries with the text SELECT *
FROM t use different cursors when they reference two different tables named t.
cluster scan
An access path for a table cluster. In an indexed table cluster, Oracle Database first
obtains the rowid of one of the selected rows by scanning the cluster index. Oracle
Database then locates the rows based on this rowid.
column group
A set of columns that is treated as a unit.
Glossary-4
cumulative statistics
column statistics
Statistics about columns that the optimizer uses to determine optimal execution plans.
Column statistics include the number of distinct column values, low value, high value,
and number of nulls.
concurrency
Simultaneous access of the same data by many users. A multiuser database
management system must provide adequate concurrency controls so that data cannot
be updated or changed improperly, compromising data integrity.
condition
A combination of one or more expressions and logical operators that returns a value of
TRUE, FALSE, or UNKNOWN.
cost
A numeric internal measure that represents the estimated resource usage for an
execution plan. The lower the cost, the more efficient the plan.
cost model
The internal optimizer model that accounts for the cost of the I/O, CPU, and network
resources that a query is predicted to use.
cumulative statistics
A count such as the number of block reads. Oracle Database generates many types of
cumulative statistics for the system, sessions, and individual SQL statements.
Glossary-5
cursor
cursor
A handle or name for a private SQL area in the PGA. Because cursors are closely
associated with private SQL areas, the terms are sometimes used interchangeably.
cursor cache
See shared SQL area.
cursor merging
Combining cursors to save space in the shared SQL area. If the optimizer creates a
plan for a bind-aware cursor, and if this plan is the same as an existing cursor, then
the optimizer can merge the cursors.
data skew
Large variations in the number of duplicate values in a column.
database operation
A set of database tasks defined by end users or application code, for example, a batch
job or ETL processing.
default plan
For an adaptive plan, the execution plan initially chosen by the optimizer using the
statistics from the data dictionary. The default plan can differ from the final plan.
disabled plan
A plan that a database administrator has manually marked as ineligible for use by the
optimizer.
dense key
A numeric key that is stored as a native integer and has a range of values.
Glossary-6
endpoint number
density
A decimal number between 0 and 1 that measures the selectivity of a column. Values
close to 1 indicate that the column is unselective, whereas values close to 0 indicate
that this column is more selective.
driving table
The table to which other tables are joined. An analogy from programming is a for loop
that contains another for loop. The outer for loop is the analog of a driving table,
which is also called an outer table.
dynamic statistics
An optimization technique in which the database executes a recursive SQL statement
to scan a small random sample of a table's blocks to estimate predicate selectivities.
enabled plan
In SQL plan management, a plan that is eligible for use by the optimizer.
endpoint number
A number that uniquely identifies a bucket in a histogram. In frequency and hybrid
histograms, the endpoint number is the cumulative frequency of endpoints. In height-
balanced histograms, the endpoint number is the bucket number.
Glossary-7
endpoint repeat count
endpoint value
An endpoint value is the highest value in the range of values in a histogram bucket.
equijoin
A join whose join condition contains an equality operator.
estimator
The component of the optimizer that determines the overall cost of a given execution
plan.
execution plan
The combination of steps used by the database to execute a SQL statement. Each step
either retrieves rows of data physically from the database or prepares them for the
user issuing the statement. You can override execution plans by using hints.
execution tree
A tree diagram that shows the flow of row sources from one step to another in an
execution plan.
expression
A combination of one or more values, operators, and SQL functions that evaluates to a
value. For example, the expression 2*2 evaluates to 4. In general, expressions assume
the data type of their components.
expression statistics
A type of extended statistics that improves optimizer estimates when a WHERE clause
has predicates that use expressions.
extended statistics
A type of optimizer statistics that improves estimates for cardinality when multiple
predicates exist or when predicates contain expressions.
extensible optimizer
An optimizer capability that enables authors of user-defined functions and indexes to
create statistics collection, selectivity, and cost functions that the optimizer uses when
choosing an execution plan. The optimizer cost model is extended to integrate
information supplied by the user to assess CPU and I/O cost.
Glossary-8
full table scan
extension
A column group or an expression. The statistics collected for column groups and
expressions are called extended statistics.
external table
A read-only table whose metadata is stored in the database but whose data in stored
in files outside the database. The database uses the metadata describing external tables
to expose their data as if they were relational tables.
filter condition
A WHERE clause component that eliminates rows from a single object referenced in a
SQL statement.
final plan
In an adaptive plan, the plan that executes to completion. The default plan can differ
from the final plan.
fixed object
A dynamic performance table or its index. The fixed objects are owned by SYS. Fixed
object tables have names beginning with X$ and are the base tables for the V$ views.
fixed plan
An accepted plan that is marked as preferred, so that the optimizer considers only the
fixed plans in the SQL plan baseline. You can use fixed plans to influence the plan
selection process of the optimizer.
frequency histogram
A type of histogram in which each distinct column value corresponds to a single
bucket. An analogy is sorting coins: all pennies go in bucket 1, all nickels go in bucket
2, and so on.
Glossary-9
global temporary table
hard parse
The steps performed by the database to build a new executable version of application
code. The database must perform a hard parse instead of a soft parse if the parsed
representation of a submitted statement does not exist in the shared SQL area.
hash cluster
A type of table cluster that is similar to an indexed cluster, except the index key is
replaced with a hash function. No separate cluster index exists. In a hash cluster, the
data is the index.
hash collision
Hashing multiple input values to the same output value.
hash function
A function that operates on an arbitrary-length input value and returns a fixed-length
hash value.
hash join
A method for joining large data sets. The database uses the smaller of two data sets to
build a hash table on the join key in memory. It then scans the larger data set, probing
the hash table to find the joined rows.
hash scan
An access path for a table cluster. The database uses a hash scan to locate rows in a
hash cluster based on a hash value. In a hash cluster, all rows with the same hash
value are stored in the same data block. To perform a hash scan, Oracle Database first
obtains the hash value by applying a hash function to a cluster key value specified by
the statement, and then scans the data blocks containing rows with that hash value.
hash table
An in-memory data structure that associates join keys with rows in a hash join. For
example, in a join of the employees and departments tables, the join key might be
the department ID. A hash function uses the join key to generate a hash value. This
hash value is an index in an array, which is the hash table.
hash value
In a hash cluster, a unique numeric ID that identifies a bucket. Oracle Database uses a
hash function that accepts an infinite number of hash key values as input and sorts
them into a finite number of buckets. Each hash value maps to the database block
Glossary-10
incremental statistics maintenance
address for the block that stores the rows corresponding to the hash key value
(department 10, 20, 30, and so on).
hashing
A mathematical technique in which an infinite set of input values is mapped to a finite
set of output values, called hash values. Hashing is useful for rapid lookups of data in
a hash table.
heap-organized table
A table in which the data rows are stored in no particular order on disk. By default,
CREATE TABLE creates a heap-organized table.
height-balanced histogram
A histogram in which column values are divided into buckets so that each bucket
contains approximately the same number of rows.
hint
An instruction passed to the optimizer through comments in a SQL statement. The
optimizer uses hints to choose an execution plan for the statement.
histogram
A special type of column statistic that provides more detailed information about the
data distribution in a table column.
hybrid histogram
An enhanced height-based histogram that stores the exact frequency of each endpoint
in the sample, and ensures that a value is never stored in multiple buckets.
implicit query
A component of a DML statement that retrieves data without a subquery. An UPDATE,
DELETE, or MERGE statement that does not explicitly include a SELECT statement uses
an implicit query to retrieve the rows to be modified.
in-memory scan
A table scan that retrieves rows from the In-Memory Column Store.
Glossary-11
index
index
Optional schema object associated with a nonclustered table, table partition, or table
cluster. In some cases indexes speed data access.
index cluster
An table cluster that uses an index to locate data. The cluster index is a B-tree index on
the cluster key.
index-organized table
A table whose storage organization is a variant of a primary B-tree index. Unlike a
heap-organized table, data is stored in primary key order.
Glossary-12
join method
index statistics
Statistics about indexes that the optimizer uses to determine whether to perform a full
table scan or an index scan. Index statistics include B-tree levels, leaf block counts, the
index clustering factor, distinct keys, and number of rows in the index.
inner join
A join of two or more tables that returns only those rows that satisfy the join condition.
inner table
In a nested loops join, the table that is not the outer table (driving table). For every
row in the outer table, the database accesses all rows in the inner table. The outer loop
is for every row in the outer table and the inner loop is for every row in the inner table.
join
A statement that retrieves data from multiple tables specified in the FROM clause of a
SQL statement. Join types include inner joins, outer joins, and Cartesian joins.
join condition
A condition that compares two row sources using an expression. The database
combines pairs of rows, each containing one row from each row source, for which the
join condition evaluates to true.
join elimination
The removal of redundant tables from a query. A table is redundant when its columns
are only referenced in join predicates, and those joins are guaranteed to neither filter
nor expand the resulting rows.
join factorization
A cost-based transformation that can factorize common computations from branches
of a UNION ALL query. Without join factorization, the optimizer evaluates each
branch of a UNION ALL query independently, which leads to repetitive processing,
including data access and joins. Avoiding an extra scan of a large base table can lead to
a huge performance improvement.
join method
A method of joining a pair of row sources. The possible join methods are nested loop,
sort merge, and hash joins. A Cartesian join requires one of the preceding join
methods
Glossary-13
join order
join order
The order in which multiple tables are joined together. For example, for each row in
the employees table, the database can read each row in the departments table. In
an alternative join order, for each row in the departments table, the database reads
each row in the employees table.
To execute a statement that joins more than two tables, Oracle Database joins two of
the tables and then joins the resulting row source to the next table. This process
continues until all tables are joined into the result.
join predicate
A predicate in a WHERE or JOIN clause that combines the columns of two tables in a
join.
key vector
A data structure that maps between dense join keys and dense grouping keys.
latch
A low-level serialization control mechanism used to protect shared data structures in
the SGA from simultaneous access.
left table
In an outer join, the table specified on the left side of the OUTER JOIN keywords (in
ANSI SQL syntax).
library cache
An area of memory in the shared pool. This cache includes the shared SQL areas,
private SQL areas (in a shared server configuration), PL/SQL procedures and
packages, and control structures such as locks and library cache handles.
maintenance window
A contiguous time interval during which automated maintenance tasks run. The
maintenance windows are Oracle Scheduler windows that belong to the window
group named MAINTENANCE_WINDOW_GROUP.
Glossary-14
optimization
materialized view
A schema object that stores a query result. All materialized views are either read-only
or updatable.
multiblock read
An I/O call that reads multiple database blocks. Multiblock reads can significantly
speed up full table scans.
NDV
Number of distinct values. The NDV is important in generating selectivity estimates.
nonequijoin
A join whose join condition does not contain an equality operator.
nonjoin column
A predicate in a WHERE clause that references only one table.
nonpopular value
In a histogram, any value that does not span two or more endpoints. Any value that is
not nonpopular is a popular value.
noworkload statistics
Optimizer system statistics gathered when the database simulates a workload.
optimization
The overall process of choosing the most efficient means of executing a SQL statement.
Glossary-15
optimizer
optimizer
Built-in database software that determines the most efficient way to execute a SQL
statement by considering factors related to the objects referenced and the conditions
specified in the statement.
optimizer environment
The totality of session settings that can affect execution plan generation, such as the
work area size or optimizer settings (for example, the optimizer mode).
optimizer goal
The prioritization of resource usage by the optimizer. Using the OPTIMIZER_MODE
initialization parameter, you can set the optimizer goal best throughput or best
response time.
optimizer statistics
Details about the database its object used by the optimizer to select the best execution
plan for each SQL statement. Categories include table statistics such as numbers of
rows, index statistics such as B-tree levels, system statistics such as CPU and I/O
performance, and column statistics such as number of nulls.
outer join
A join condition using the outer join operator (+) with one or more columns of one of
the tables. The database returns all rows that meet the join condition. The database
also returns all rows from the table without the outer join operator for which there are
no matching rows in the table with the outer join operator.
Glossary-16
pending statistics
outer table
See driving table
parallel execution
The application of multiple CPU and I/O resources to the execution of a single
database operation.
parallel query
A query in which multiple processes work together simultaneously to run a single
SQL query. By dividing the work among multiple processes, Oracle Database can run
the statement more quickly. For example, four processes retrieve rows for four
different quarters in a year instead of one process handling all four quarters by itself.
parent cursor
The cursor that stores the SQL text and other minimal information for a SQL
statement. The child cursor contains the plan, compilation environment, and other
information. When a statement first executes, the database creates both a parent and
child cursor in the shared pool.
parse call
A call to Oracle to prepare a SQL statement for execution. The call includes
syntactically checking the SQL statement, optimizing it, and then building or locating
an executable form of that statement.
parsing
The stage of SQL processing that involves separating the pieces of a SQL statement
into a data structure that can be processed by other routines.
A hard parse occurs when the SQL statement to be executed is either not in the shared
pool, or it is in the shared pool but it cannot be shared. A soft parse occurs when a
session attempts to execute a SQL statement, and the statement is already in the
shared pool, and it can be used.
partition-wise join
A join optimization that divides a large join of two tables, one of which must be
partitioned on the join key, into several smaller joins.
pending statistics
Unpublished optimizer statistics. By default, the optimizer uses published statistics
but does not use pending statistics.
Glossary-17
performance feedback
performance feedback
This form of automatic reoptimization helps improve the degree of parallelism
automatically chosen for repeated SQL statements when PARALLEL_DEGREE_POLICY
is set to ADAPTIVE.
plan evolution
The manual change of an unaccepted plan in the SQL plan history into an accepted
plan in the SQL plan baseline.
plan generator
The part of the optimizer that tries different access paths, join methods, and join orders
for a given query block to find the plan with the lowest cost.
plan selection
The optimizer's attempt to find a matching plan in the SQL plan baseline for a
statement after performing a hard parse.
plan verification
Comparing the performance of an unaccepted plan to a plan in a SQL plan baseline
and ensuring that it performs better.
popular value
In a histogram, any value that spans two or more endpoints. Any value that is not
popular is an nonpopular value.
predicate pushing
A transformation technique in which the optimizer "pushes" the relevant predicates
from the containing query block into the view query block. For views that are not
merged, this technique improves the subplan of the unmerged view because the
database can use the pushed-in predicates to access indexes or to use as filters.
Glossary-18
result set
projection view
An optimizer-generated view that appear in queries in which a DISTINCT view has
been merged, or a GROUP BY view is merged into an outer query block that also
contains GROUP BY, HAVING, or aggregates.
See simple view merging, complex view merging.
query
An operation that retrieves data from tables or views. For example, SELECT * FROM
employees is a query.
query block
A top-level SELECT statement, subquery, or unmerged view
query optimizer
See optimizer.
recursive SQL
Additional SQL statements that the database must issue to execute a SQL statement
issued by a user. The generation of recursive SQL is known as a recursive call. For
example, the database generates recursive calls when data dictionary information is
not available in memory and so must be retrieved from disk.
reoptimization
See automatic reoptimization.
response time
The time required to complete a unit of work.
See throughput.
result set
In a query, the set of rows generated by the execution of a cursor.
Glossary-19
right join tree
right table
In an outer join, the table specified on the right side of the OUTER JOIN keywords (in
ANSI SQL syntax).
rowid
A globally unique address for a row in a table.
row set
A set of rows returned by a step in an execution plan.
row source
An iterative control structure that processes a set of rows in an iterated manner and
produces a row set.
sampling
Gathering statistics from a random subset of rows in a table.
selectivity
A value indicating the proportion of a row set retrieved by a predicate or combination
of predicates, for example, WHERE last_name = 'Smith'. A selectivity of 0 means
that no rows pass the predicate test, whereas a value of 1 means that all rows pass the
test.
The adjective selective means roughly "choosy." Thus, a highly selective query returns a
low proportion of rows (selectivity close to 0), whereas an unselective query returns a
high proportion of rows (selectivity close to 1).
Glossary-20
SQL Access Advisor
semijoin
A join that returns rows from the first table when at least one match exists in the
second table. For example, you list departments with at least one employee. The
difference between a semijoin and a conventional join is that rows in the first table are
returned at most once. Semijoins use the EXISTS or IN constructs.
shared cursor
A shared SQL area that is used by multiple SQL statements.
shared pool
Portion of the SGA that contains shared memory constructs such as shared SQL areas.
SMB
See SQL management base (SMB).
soft parse
Any parse that is not a hard parse. If a submitted SQL statement is the same as a
reusable SQL statement in the shared pool, then Oracle Database reuses the existing
code. This reuse of code is also called a library cache hit.
Glossary-21
SQL compilation
SQL compilation
In the context of Oracle SQL processing, this term refers collectively to the phases of
parsing, optimization, and plan generation.
SQL handle
A string value derived from the numeric SQL signature. Like the signature, the handle
uniquely identifies a SQL statement. It serves as a SQL search key in user APIs.
SQL ID
For a specific SQL statement, the unique identifier of the parent cursor in the library
cache. A hash function applied to the text of the SQL statement generates the SQL ID.
The V$SQL.SQL_ID column displays the SQL ID.
SQL incident
In the fault diagnosability infrastructure of Oracle Database, a single occurrence of a
SQL-related problem. When a problem (critical error) occurs multiple times, the
database creates an incident for each occurrence. Incidents are timestamped and
tracked in the Automatic Diagnostic Repository (ADR).
Glossary-22
SQL test case builder
SQL processing
The stages of parsing, optimization, row source generation, and execution of a SQL
statement.
SQL profile
A set of auxiliary information built during automatic tuning of a SQL statement. A
SQL profile is to a SQL statement what statistics are to a table. The optimizer can use
SQL profiles to improve cardinality and selectivity estimates, which in turn leads the
optimizer to select better plans.
SQL profiling
The verification and validation by the Automatic Tuning Advisor of its own estimates.
SQL signature
A numeric hash value computed using a SQL statement text that has been normalized
for case insensitivity and white space. It uniquely identifies a SQL statement. The
database uses this signature as a key to maintain SQL management objects such as
SQL profiles, SQL plan baselines, and SQL patches.
Glossary-23
SQL trace file
SQL tuning
The process of improving SQL statement efficiency to meet measurable goals.
star schema
A relational schema whose design represents a dimensional data model. The star
schema consists of one or more fact tables and one or more dimension tables that are
related through foreign keys.
statistics feedback
A form of automatic reoptimization that automatically improves plans for repeated
queries that have cardinality misestimates. The optimizer may estimate cardinalities
incorrectly for many reasons, such as missing statistics, inaccurate statistics, or
complex predicates.
stored outline
A set of hints for a SQL statement. The hints in stored outlines direct the optimizer to
choose a specific plan for the statement.
subplan
A portion of an adaptive plan that the optimizer can switch to as an alternative at run
time. A subplan can consist of multiple operations in the plan. For example, the
optimizer can treat a join method and the corresponding access path as one unit when
determining whether to change the plan at run time.
subquery
A query nested within another SQL statement. Unlike implicit queries, subqueries use
a SELECT statement to retrieve data.
Glossary-24
tuning mode
subquery unnesting
A transformation technique in which the optimizer transforms a nested query into an
equivalent join statement, and then optimizes the join.
synopsis
A set of auxiliary statistics gathered on a partitioned table when the INCREMENTAL
value is set to true.
system statistics
Statistics that enable the optimizer to use CPU and I/O characteristics. Index statistics
include B-tree levels, leaf block counts, clustering factor, distinct keys, and number of
rows in the index.
table cluster
A schema object that contains data from one or more tables, all of which have one or
more columns in common. In table clusters, the database stores together all the rows
from all tables that share the same cluster key.
table expansion
A transformation technique that enables the optimizer to generate a plan that uses
indexes on the read-mostly portion of a partitioned table, but not on the active portion
of the table.
table statistics
Statistics about tables that the optimizer uses to determine table access cost, join
cardinality, join order, and so on. Table statistics include row counts, block counts,
empty blocks, average free space per block, number of chained rows, average row
length, and staleness of the statistics on the table.
throughput
The amount of work completed in a unit of time.
See response time.
tuning mode
One of the two optimizer modes. When running in tuning mode, the optimizer is
known as the Automatic Tuning Optimizer. In tuning mode, the optimizer
determines whether it can further improve the plan produced in normal mode. The
optimizer output is not an execution plan, but a series of actions, along with their
rationale and expected benefit for producing a significantly better plan.
Glossary-25
unaccepted plan
unaccepted plan
A plan for a statement that is in the SQL plan history but has not been added to the
SQL plan management.
unselective
A relatively large fraction of rows from a row set. A query becomes more unselective
as the selectivity approaches 1. For example, a query that returns 999,999 rows from a
table with one million rows is unselective. A query of the same table that returns one
row is selective.
V$ view
See dynamic performance view.
vector I/O
A type of I/O in which the database obtains a set of rowids, sends them batched in an
array to the operating system, which performs the read.
view merging
The merging of a query block representing a view into the query block that contains it.
View merging can improve plans by enabling the optimizer to consider additional join
orders, access methods, and other transformations.
workload statistics
Optimizer statistics for system activity in a specified time period.
Glossary-26
Index
A bitmap indexes
inlist iterator, 7-16
access paths on joins, A-10
execution plans, 6-1 when to use, A-10
full table scan, 10-6 BOOLEAN data type, 8-18
full table scans, 11-1 BYTES column
adaptive plans PLAN_TABLE table, 7-18, 7-31
cardinality misestimates, 4-12
join methods, 4-12
optimizer statistics collector, 4-12 C
parallel distribution methods, 4-15 cardinality, 1-5, 4-5, 4-12, 4-18, 4-20, 6-2, 8-29, 10-4,
reporting mode, 14-3 10-18, 11-1, 11-4
subplans, 4-12 CARDINALITY column
adaptive query optimization PLAN_TABLE table, 7-18, 7-31
adaptive plans, 4-11, 7-2, 7-28, 14-3, 17-2 cartesian joins, 9-21
controlling, 14-8 child cursors, 15-4
dynamic statistics, 10-13 clusters
adaptive statistics sorted hash, A-12
automatic reoptimization, 4-17 column group statistics, 10-18
dynamic statistics, 4-17 column groups
SQL plan directives, 4-20, 13-11 optimizer statistics, 13-12
ADDM, 1-5 columns
ALTER SESSION statement cardinality, 4-5
examples, 18-10 to index, A-3
antijoins, 9-3 compilation, SQL, 10-17, 10-18, 10-28
applications composite indexes, A-4
implementing, 2-2 composite partitioning
automatic reoptimization examples of, 7-11
cardinality misestimates, 4-18 concurrent statistics gathering, 12-21, 12-25, 5
performance feedback, 4-19 consistent mode
statistics feedback, 4-18 TKPROF, 18-24
automatic statistics collection, 12-3 constraints, A-6
Automatic Tuning Optimizer, 1-5 COST column
Automatic Workload Repository (AWR), 1-5 PLAN_TABLE table, 7-18, 7-31
current mode
TKPROF, 18-24
B CURSOR_NUM column
big bang rollout strategy, 2-4 TKPROF_TABLE table, 18-13
bind variable peeking, 15-12 CURSOR_SHARING initialization parameters, 15-2
bind variables cursors
bind peeking, 15-12 about, 15-1
bind-aware cursors, 15-23 bind variable peeking, 15-12
bind-sensitive cursors, 15-20 bind-aware, 15-23
Index-1
cursors (continued) DEPTH column (continued)
bind-sensitive, 15-20 TKPROF_TABLE table, 18-13
child, 15-4 designs
parent, 15-4, 15-5 debugging, 2-3
sharing, 15-1, 15-2 testing, 2-3
validating, 2-3
development environments, 2-2
D DIAGNOSTIC_DEST initialization parameter, 18-9
data disabled constraints, A-6
modeling, 2-1 DISTRIBUTION column
data blocks, 3-9 PLAN_TABLE table, 7-20, 7-29
data dictionary cache, 3-4 domain indexes
data flow operator (DFO), 5-17 and EXPLAIN PLAN, 7-16
Data Pump using, A-10
Export utility dynamic statistics
statistics on system-generated columns controlling, 13-1
names, 13-34 process, 13-2
Import utility sampling levels, 13-2
copying statistics, 13-34 when to use, 13-5
data skew, 11-1
data types
BOOLEAN, 8-18 E
database operations enabled constraints, A-6
composite, 1-7, 16-1 end-to-end application tracing
definition, 1-7, 16-1 action and module names, 18-2
simple, 1-7, 16-1 creating a service, 18-2
database operations, monitoring DBMS_APPLICATION_INFO package, 18-2
composite, 16-5 DBMS_MONITOR package, 18-2
composite operations, 16-1 endpoint repeat counts, in histograms, 11-18
creating database operations, 16-10 enforced constraints, A-6
enabling with hints, 16-9 examples
enabling with initialization parameters, 16-9 ALTER SESSION statement, 18-10
Enterprise Manager interface, 16-6 EXPLAIN PLAN output, 18-16
generating a report, 16-11 EXECUTE_TASK procedure, 21-13
PL/SQL interface, 16-6 execution plans
purpose, 16-2 adaptive, 4-11, 7-2, 7-28
real-time SQL, 16-1 examples, 18-12
simple operations, 16-1 overview of, 6-1
DATE_OF_INSERT column TKPROF, 18-13, 18-21
TKPROF_TABLE table, 18-13 V$ views, 7-28
DB_FILE_MULTIBLOCK_READ_COUNT viewing with the utlxpls.sql script, 6-5
initialization parameter, 8-6, 8-7 execution trees, 3-7
DBMS_ADVISOR package, 21-1 EXPLAIN PLAN statement
DBMS_MONITOR package access paths, 8-9, 8-11
end-to-end application tracing, 18-2 and full partition-wise joins, 7-14
DBMS_SQLTUNE package and partial partition-wise joins, 7-13
SQL Tuning Advisor, 20-25 and partitioned objects, 7-9
DDL (data definition language)
basic steps, 6-5
processing of, 3-9
examples of output, 18-16
deadlocks, 3-2
invoking with the TKPROF program, 18-21
debugging designs, 2-3
PLAN_TABLE table, 6-5
dedicated server, 3-4
restrictions, 6-4
dense keys
viewing the output, 6-5
dense grouping keys, 5-17
extended statistics, 10-4
dense join keys, 5-17
extensions, 10-18
density, histogram, 11-5
DEPTH column
Index-2
F in-memory aggregation (continued)
controls, 5-20
fixed objects how it works, 5-17
gathering statistics for, 12-1, 12-18 purpose, 5-17
frequency histograms, 11-6, 11-10 in-memory table scans
full outer joins, 9-28 controls, 8-10
full partition-wise joins, 7-14 example, 8-11
full table scans, 10-6, 11-1 when chosen, 8-10
function-based indexes, A-8 incremental statistics, 12-31, 12-33
index clustering factor, 10-6
G index statistics
index clustering factor, 10-6
global temporary tables, 10-10 indexes
avoiding the use of, A-5
bitmap, A-10
H
choosing columns for, A-3
hard parsing, 2-2, 3-4 composite, A-4
hash clusters domain, A-10
sorted, A-12 dropping, A-2
hash joins enforcing uniqueness, A-6
cost-based optimization, 9-3 ensuring the use of, A-5
hash partitions function-based, A-8
examples of, 7-10 improving selectivity, A-4
hashing, A-12 low selectivity, A-5
height-balanced histograms, 11-14 modifying values of, A-3
high-load SQL
non-unique, A-6
tuning, 12-2, 20-25
re-creating, A-5
hints, optimizer
scans, 8-18
FULL, A-5
selectivity of, A-3
NO_INDEX, A-5
initialization parameters
NO_MONITOR, 16-9
DIAGNOSTIC_DEST, 18-9
histograms
inner loop, in nested loops joins, 9-6
cardinality algorithms, 11-4
criteria for creation, 11-3
data skew, 11-1 J
definition, 11-1
joins
density, 11-5 antijoins, 9-3
endpoint numbers, 11-4 cartesian, 9-21
endpoint repeat counts, 11-18 full outer, 9-28
endpoint values, 11-4 hash, 9-15
frequency, 11-6, 11-10 nested loops, 3-7, 9-6
height-balanced, 11-14 nested loops and cost-based optimization, 9-3
hybrid, 11-18, 11-20 order, 14-14
NDV, 11-1 outer, 9-25
nonpopular values, 11-4 partition-wise
popular values, 11-4 examples of full, 7-14
purpose, 11-1 examples of partial, 7-13
top frequency, 11-10 full, 7-14
hybrid histograms, 11-18, 11-20 semijoins, 9-3
sort-merge and cost-based optimization, 9-3
I
I/O K
reducing, A-4 key vectors, 5-17
ID column
PLAN_TABLE table, 7-18, 7-29
in-memory aggregation
Index-3
L optimizer environment, 3-5
optimizer hints
latches FULL, A-5
parsing and, 3-4 MONITOR, 16-9
library cache, 3-4 NO_INDEX, A-5
library cache miss, 3-4 optimizer statistics
locks adaptive statistics, 4-17
deadlocks, 3-2 automatic collection, 12-3
basic topics, 12-1
M bulk loads, 10-14
cardinality, 11-1
manual plan capture, 23-5 collection, 12-1
modeling column group, 10-18
data, 2-1 column groups, 13-11, 13-12
multiversion read consistency, 3-9 dynamic, 10-13, 10-17, 12-21, 13-1, 17-2
extended, 10-4
N gathering concurrently, 12-21, 5
gathering in parallel, 12-25
NDV, 11-1
getting, 12-8
nested loop joins
histograms, 11-1
how they work, 9-6
incremental, 12-31, 12-33
nested loops
index, 10-5
driving table, 9-6
nested loops joins pluggable databases and, 12-3
cost-based optimization, 9-3 preferences, 12-8
NO_INDEX hint, A-5 setting, 12-8
nonpopular values, in histograms, 11-4 SQL plan directives, 10-18, 13-11
NOT IN subquery, 9-3 system, 12-35
temporary, 10-10
optimizer statistics collection, 12-1
O optimizer statistics collectors, 4-12
OBJECT_INSTANCE column OPTIONS column
PLAN_TABLE table, 7-16, 7-29 PLAN_TABLE table, 7-16, 7-29
OBJECT_NAME column OTHER column
PLAN_TABLE table, 7-16, 7-29 PLAN_TABLE table, 7-20, 7-32
OBJECT_NODE column OTHER_TAG column
PLAN_TABLE table, 7-16, 7-29 PLAN_TABLE table, 7-19, 7-31
OBJECT_OWNER column outer joins, 9-25
PLAN_TABLE table, 7-16, 7-29 outer loops, in nested loops join, 9-6
OBJECT_TYPE column
PLAN_TABLE table, 7-17, 7-29 P
OPERATION column
PLAN_TABLE table, 7-16, 7-29 packages
optimization, SQL, 4-2 DBMS_ADVISOR, 21-1
optimizer parallel execution
adaptive, 7-2 gathering statistics, 12-25
definition, 4-1 parent cursors, 15-4, 15-5
environment, 3-5 PARENT_ID column
estimator, 4-5 PLAN_TABLE table, 7-18, 7-30
execution, 3-7 parse calls, 3-2
goals, 14-7 parsing, SQL
purpose of, 4-1 hard, 2-2
row sources, 3-5, 3-6 hard parse, 3-4
statistics, 14-10 parse trees, 3-7
throughput, 14-7 soft, 2-2
OPTIMIZER column soft parse, 3-4
PLAN_TABLE, 7-17, 7-29 partition maintenance operations, 12-31
Index-4
PARTITION_ID column private SQL areas
PLAN_TABLE table, 7-20, 7-32 parsing and, 3-2
PARTITION_START column processes
PLAN_TABLE table, 7-19, 7-32 dedicated server, 3-4
PARTITION_STOP column programming languages, 2-2
PLAN_TABLE table, 7-20, 7-32
partition-wise joins
full, 7-14
Q
full, and EXPLAIN PLAN output, 7-14 queries
partial, and EXPLAIN PLAN output, 7-13 avoiding the use of indexes, A-5
partitioned objects ensuring the use of indexes, A-5
and EXPLAIN PLAN statement, 7-9 query transformations
partitioning in-memory aggregation, 5-16
examples of, 7-10
examples of composite, 7-11
hash, 7-9
R
range, 7-9 range
start and stop columns, 7-10 examples of partitions, 7-10
performance partitions, 7-9
viewing execution plans, 6-5 Real-Time Database Operations, 1-7
PLAN_TABLE table Real-Time SQL Monitoring, 1-7, 16-1
BYTES column, 7-18, 7-31 Real-World Performance
CARDINALITY column, 7-18, 7-31 cursor sharing, 15-1
COST column, 7-18, 7-31 recursive calls, 18-15
creating, 6-5 recursive SQL, 3-9, 10-13, 10-28
displaying, 6-7 REMARKS column
DISTRIBUTION column, 7-20, 7-29 PLAN_TABLE table, 7-16, 7-29
ID column, 7-18, 7-29 reoptimization, automatic
OBJECT_INSTANCE column, 7-16, 7-29 cardinality misestimates, 4-18
OBJECT_NAME column, 7-16, 7-29 performance feedback, 4-19
OBJECT_NODE column, 7-16, 7-29 statistics feedback, 4-18
OBJECT_OWNER column, 7-16, 7-29 result sets, SQL, 3-6, 3-8
OBJECT_TYPE column, 7-17, 7-29 rollout strategies
OPERATION column, 7-16, 7-29 big bang approach, 2-4
OPTIMIZER column, 7-17, 7-29 trickle approach, 2-4
OPTIONS column, 7-16, 7-29 row source generation, 3-5
OTHER column, 7-20, 7-32 rowids
OTHER_TAG column, 7-19, 7-31 table access by, 8-7
PARENT_ID column, 7-18, 7-30 rows
PARTITION_ID column, 7-20, 7-32 row set, 3-6
PARTITION_START column, 7-19, 7-32 row source, 3-6
PARTITION_STOP column, 7-20, 7-32 rowids used to locate, 8-7
POSITION column, 7-18, 7-31
REMARKS column, 7-16, 7-29 S
SEARCH_COLUMNS column, 7-18, 7-29
SAMPLE BLOCK clause, 8-8
STATEMENT_ID column, 7-16, 7-29
SAMPLE clause, 8-8
TIMESTAMP column, 7-16, 7-29
pluggable databases sample table scans, 8-8
automatic optimizer statistics collection, 12-3 scans
in-memory, 8-9
manageability features, 12-3
sample table, 8-8
SQL management base, 23-9
SEARCH_COLUMNS column
SQL Tuning Advisor, 20-1, 21-1
PLAN_TABLE table, 7-18, 7-29
SQL tuning sets, 19-2
SELECT statement
popular values, in histograms, 11-4
SAMPLE clause, 8-8
POSITION column
selectivity
PLAN_TABLE table, 7-18, 7-31
creating indexes, A-3
Index-5
selectivity (continued) SQL trace facility
improving for an index, A-4 output, 18-24
indexes, A-5 statement truncation, 18-12
semijoins, 9-3 trace files, 18-9
shared pool SQL trace files, 1-8
parsing check, 3-3 SQL tuning
shared SQL areas, 3-3, 15-2 definition, 1-1
soft parsing, 2-2, 3-4 introduction, 1-1
sort merge joins tools overview, 1-4
cost-based optimization, 9-3 SQL Tuning Advisor
SQL administering with APIs, 20-25
execution, 3-7 input sources, 20-4, 21-3
optimization, 4-2 pluggable databases and, 20-1, 21-1
parsing, 3-2 using, 12-2, 20-25
recursive, 3-9 SQL tuning sets
result sets, 3-6, 3-8 pluggable databases and, 19-2
stages of processing, 8-2, 8-11 SQL Tuning Sets
SQL Access Advisor managing with APIs, 19-1
constants, 21-32 SQL_STATEMENT column
EXECUTE_TASK procedure, 21-13 TKPROF_TABLE, 18-13
SQL compilation, 10-17, 10-18, 10-28 SQL, recursive, 10-28, 13-1
SQL management base start columns
pluggable databases and, 23-9 in partitioning and EXPLAIN PLAN statement,
SQL parsing 7-10
parse calls, 3-2 STATEMENT_ID column
SQL Performance Analyzer, 1-6 PLAN_TABLE table, 7-16, 7-29
SQL plan baselines statistics, optimizer
displaying, 23-19 adaptive statistics, 4-17
SQL plan capture, 23-4 automatic collection, 12-3
SQL plan directives bulk loads, 10-14
cardinality misestimates, 10-18 cardinality, 11-1
managing, 13-40 collection, 12-1
SQL plan management column group, 10-18
automatic plan capture, 23-4 column groups, 13-11, 13-15
introduction, 23-1 dynamic, 10-13, 10-17, 12-21, 13-1, 17-2
manual plan capture, 23-5 dynamic statistics, 10-26
plan capture, 23-1 exporting and importing, 13-33
plan evolution, 23-2, 23-7 extended, 10-4
plan selection, 23-1, 23-6 gathering concurrently, 12-21
plan verification, 23-7 incremental, 12-31, 12-33
purpose, 23-2 index, 10-5
SQL plan baselines, 23-1 limitations on restoring previous versions, 13-28
SQL plan capture, 23-4 preferences, 12-8
SQL processing system, 10-11, 12-35
semantic check, 3-3 user-defined, 10-12
shared pool check, 3-3 stop columns
stages, 3-1 in partitioning and EXPLAIN PLAN statement,
syntax check, 3-3 7-10
SQL profiles subqueries
and SQL plan baselines, 23-3 NOT IN, 9-3
SQL statements system statistics, 12-35
avoiding the use of indexes, A-5
ensuring the use of indexes, A-5
T
execution plans of, 6-1
modifying indexed data, A-3 table statistics, 10-3
SQL Test Case Builder, 17-1 temporary tables, global, 10-10
SQL test cases, 17-1 testing designs, 2-3
Index-6
throughput U
optimizer goal, 14-7
TIMESTAMP column uniqueness, A-6
PLAN_TABLE table, 7-16, 7-29 USER_ID column, TKPROF_TABLE, 18-13
TKPROF program
editing the output SQL script, 18-13
V
example of output, 18-16
generating the output SQL script, 18-13 V$SQL_PLAN view
row source operations, 18-25 using to display execution plan, 6-4
using the EXPLAIN PLAN statement, 18-21 V$SQL_PLAN_STATISTICS view
wait event information, 18-25 using to display execution plan statistics, 6-4
TKPROF_TABLE, 18-13 V$SQL_PLAN_STATISTICS_ALL view
top frequency histograms, 11-10 using to display execution plan information, 6-4
tracing V$SQLAREA view, 15-5
consolidating with trcsess, 18-19 validating designs, 2-3
identifying files, 18-9
trcsess utility, 18-19 W
trickle rollout strategy, 2-4
tuning workloads, 2-3
logical structure, A-1
Index-7
Index-8