What is the Oracle query optimizer?
In the world of Oracle Database, the Query Optimizer is the "Navigation App" (like Waze or Google Maps) for your SQL statements.
When you type SELECT * FROM sales WHERE region = 'South', you are telling Oracle what you want, but not how to get it. The Optimizer’s job is to look at all possible routes—scanning every row, using an index, or joining tables in different orders—and choose the most efficient path.
Modern Oracle versions use the Cost-Based Optimizer (CBO). For every SQL query, the Optimizer calculates the "cost" of multiple execution plans.
Cost is a numeric value representing the estimated resource usage (mostly I/O and CPU) required to run the query.
The Winner: The plan with the lowest cost is the one that gets executed.
The Optimizer isn't guessing; it’s a highly advanced mathematical engine that relies on several inputs:
Oracle collects data about your data, stored in the Data Dictionary. This includes:
Table Stats: How many rows are in the table?
Column Stats: How many "unique" values are in a column? (e.g., Are there 2 regions or 2,000?)
Index Stats: How tall is the index "tree"?
The Optimizer decides how to physically grab the data:
Full Table Scan (FTS): Reading every block in the table (good for small tables or when you need 90% of the rows).
Index Range Scan: Using an index to jump straight to specific rows (good for finding a needle in a haystack).
If you are joining two tables, it decides the "how":
Nested Loops: Like two FOR loops in programming (best for small datasets).
Hash Join: Building a temporary "hash table" in memory (best for large datasets).
Parsing: Oracle checks the syntax and permissions.
Transformation: The Optimizer might rewrite your SQL into a more efficient version (e.g., turning a subquery into a join).
Estimation: It calculates the cost based on the statistics.
Plan Generation: It picks the "Cheapest" plan and hands it to the execution engine.
The Optimizer is only as good as its "map." The #1 cause of slow SQL is Stale Statistics.
If your statistics say a table has 10 rows, but it actually has 10 million, the Optimizer will choose a "Nested Loop" (meant for small data), and your query will crawl.
The Fix: Regularly gather statistics using DBMS_STATS.GATHER_TABLE_STATS.
| Feature | Cost-Based (CBO) | Rule-Based (RBO - Obsolete) |
| Logic | Uses math and data statistics. | Uses a fixed set of "ranked" rules. |
| Intelligence | Adapts to your specific data. | Blindly follows rules regardless of table size. |
| Modern Support | Default in all versions (12c-23c). | No longer supported/updated. |
You can peak inside the Optimizer’s brain using the EXPLAIN PLAN command or by querying the library cache:
EXPLAIN PLAN FOR
SELECT * FROM employees WHERE department_id = 10;
SELECT * FROM TABLE(dbms_xplan.display);
This will show you exactly which path the Optimizer chose and what it estimated the "cost" to be.
Sometimes, you know more about the data than the Optimizer does. You can "suggest" a path using a Hint:
SELECT /*+ INDEX(emp_idx) */ * FROM employees ...
Warning: Use hints sparingly! If your data changes, a hint might force an inefficient path later on.