Introduction
High CPU usage in an Oracle Database can lead to sluggish application performance, delayed queries, and frustrated users. As a DBA or developer, pinpointing the root cause and resolving it is critical to maintaining a healthy database environment. This comprehensive guide explores the common causes of high CPU usage, provides actionable troubleshooting steps, and includes real-life examples with scripts to help you diagnose and fix issues. Whether you're new to Oracle or an experienced professional, this tutorial covers basic to advanced techniques, best practices, and standards to keep your database running smoothly.
Common Causes of High CPU Usage
High CPU usage in Oracle Database can stem from various factors. Understanding these causes is the first step toward effective troubleshooting:
Inefficient SQL Queries: Poorly optimized queries with excessive logical reads, complex joins, or nested loops.
Session Contention: Multiple sessions competing for CPU resources, often due to high concurrency.
Parsing Overhead: Excessive hard parsing caused by non-reusable SQL statements.
Background Processes: Oracle background processes like DBWn or LGWR consuming CPU.
Application Design Issues: Inefficient application logic sending repetitive or poorly structured queries.
System Resource Constraints: Limited CPU cores or overcommitted server resources.
External Factors: Other applications or processes on the server competing for CPU.
Step 1: Identifying High CPU Usage
Before resolving high CPU usage, you need to confirm it’s happening and identify the contributing factors.
1.1 Using V$SYSSTAT and V$OSSTAT
The V$SYSSTAT view provides database-level CPU usage, while V$OSSTAT shows OS-level CPU metrics.
Example Query to Check CPU Usage
SELECT
s.name,
s.value / 100 AS cpu_seconds
FROM
v$sysstat s
WHERE
s.name LIKE '%CPU used%';
SELECT
stat_name,
value
FROM
v$osstat
WHERE
stat_name IN ('NUM_CPUS', 'BUSY_TIME', 'IDLE_TIME');
Explanation:
CPU used by this session in V$SYSSTAT shows CPU time consumed by database sessions (in centiseconds).
V$OSSTAT provides the number of CPUs and their busy/idle times.
High BUSY_TIME relative to IDLE_TIME indicates CPU contention.
Real-Life Scenario: For an inventory management system, users report slow response times during peak hours. The above query shows cpu_seconds spiking to 500 seconds and BUSY_TIME at 80% of total CPU time, confirming high CPU usage.
1.2 Using Automatic Workload Repository (AWR)
AWR reports provide a detailed breakdown of CPU usage over time.
Steps:
Run the AWR report: @$ORACLE_HOME/rdbms/admin/awrrpt.sql
Select a snapshot range (e.g., last 1 hour).
Check the “Top Timed Events” section for CPU-related events like “CPU + Wait for CPU.”
Pros:
Comprehensive view of CPU usage across workloads.
Identifies top CPU-consuming SQL statements.
Cons:
Requires Diagnostic Pack license.
Can be complex for beginners.
Alternative: Use Active Session History (ASH) for real-time insights without a license.
ASH Query Example:
SELECT
sql_id,
COUNT(*) AS session_count,
SUM(cpu_time_total) / 1000000 AS cpu_seconds
FROM
v$active_session_history
WHERE
sample_time > SYSDATE - 1/24 -- Last hour
AND session_state = 'ON CPU'
GROUP BY
sql_id
ORDER BY
cpu_seconds DESC
FETCH FIRST 5 ROWS ONLY;
Step 2: Pinpointing CPU-Intensive Queries
Once high CPU usage is confirmed, identify the queries or sessions driving it.
2.1 Using V$SQL
The V$SQL view helps identify CPU-intensive queries based on cpu_time.
Example Query:
SELECT
sql_id,
sql_text,
executions,
cpu_time / 1000000 AS cpu_seconds,
buffer_gets
FROM
v$sql
WHERE
cpu_time > 1000000 -- Queries using > 1 second CPU
AND executions > 0
ORDER BY
cpu_time DESC
FETCH FIRST 10 ROWS ONLY;
Observation: Queries with high cpu_time and buffer_gets indicate excessive logical reads, often due to inefficient SQL.
2.2 Using V$SESSION
Identify sessions consuming CPU in real time.
Example Query:
SELECT
s.sid,
s.serial#,
s.username,
s.sql_id,
s.status,
s.cpu_usage
FROM
v$session s
WHERE
s.status = 'ACTIVE'
AND s.cpu_usage > 0
ORDER BY
s.cpu_usage DESC;
Real-Life Scenario: In the inventory system, the V$SQL query reveals a sql_id = 'xyz789' consuming 10 CPU seconds per execution due to a complex report query scanning a large ORDERS table.
Step 3: Analyzing Query Execution Plans
High CPU usage often results from suboptimal execution plans. Analyze them to identify inefficiencies.
3.1 Using EXPLAIN PLAN
Generate the execution plan for a suspect query.
Example:
EXPLAIN PLAN FOR
SELECT o.order_id, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date > SYSDATE - 30;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Sample Output:
------------------------------------------------------
| Id | Operation | Name | Rows | Cost |
------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 2000|
| 1 | HASH JOIN | | 10000 | 2000|
| 2 | TABLE ACCESS FULL| ORDERS | 50000 | 1200|
| 3 | TABLE ACCESS FULL| CUSTOMERS | 500 | 300|
------------------------------------------------------
Observation: The TABLE ACCESS FULL on ORDERS suggests a full table scan, which can be CPU-intensive for large tables.
3.2 Using DBMS_XPLAN.DISPLAY_CURSOR
For real-time plans, use DBMS_XPLAN.DISPLAY_CURSOR.
Example:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('xyz789', NULL, 'ALLSTATS LAST'));
Pros:
Shows actual CPU usage and row counts.
Highlights discrepancies between estimated and actual costs.
Cons:
Requires sql_id and cursor information.
May need elevated permissions.
Best Practice: Compare estimated and actual plans to identify optimizer misjudgments.
Step 4: Resolving High CPU Usage
With the problematic queries or sessions identified, apply these techniques to reduce CPU usage.
4.1 Optimizing SQL Queries
Rewrite inefficient queries to reduce CPU consumption.
Example: Inefficient Query
SELECT order_id
FROM orders
WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2025-08-01';
Optimized Version:
SELECT order_id
FROM orders
WHERE order_date = TO_DATE('2025-08-01', 'YYYY-MM-DD');
Why It’s Better:
Avoids function-based operations on columns, enabling index usage.
Reduces CPU overhead from data conversions.
Real-Life Scenario: In the inventory system, rewriting a report query to avoid TO_CHAR reduced CPU usage by 40%.
4.2 Adding Indexes
Indexes reduce logical reads, lowering CPU usage.
Example: Create an index on order_date.
CREATE INDEX idx_orders_date ON orders(order_date);
After Index Execution Plan:
------------------------------------------------------
| Id | Operation | Name | Rows | Cost |
------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 400|
| 1 | HASH JOIN | | 10000 | 400|
| 2 | INDEX RANGE SCAN | IDX_ORDERS_DATE | 10000 | 100|
| 3 | TABLE ACCESS FULL | CUSTOMERS | 500 | 300|
------------------------------------------------------
Pros:
Reduces CPU usage by minimizing logical reads.
Speeds up query execution.
Cons:
Increases storage and DML overhead.
Requires regular maintenance.
Best Practice: Use composite indexes for multi-column filters, e.g., CREATE INDEX idx_orders_date_cust ON orders(order_date, customer_id).
4.3 Reducing Hard Parsing
Excessive hard parsing due to non-reusable SQL consumes CPU. Use bind variables to promote cursor sharing.
Example: Non-Reusable SQL
SELECT product_name FROM products WHERE product_id = 123;
SELECT product_name FROM products WHERE product_id = 456;
Optimized with Bind Variables:
SELECT product_name FROM products WHERE product_id = :prod_id;
Pros:
Reduces CPU usage from parsing.
Improves scalability for high-concurrency systems.
Cons:
Requires application code changes.
May not suit all dynamic SQL scenarios.
Best Practice: Set CURSOR_SHARING = FORCE at the database level for legacy applications, but test thoroughly.
4.4 Managing Session Contention
High concurrency can lead to CPU contention. Limit parallel sessions or adjust resource allocation.
Example: Limit sessions per user.
ALTER PROFILE default LIMIT SESSIONS_PER_USER 5;
Alternative: Use Resource Manager to prioritize CPU allocation.
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
plan => 'DAYTIME_PLAN',
group_or_subplan => 'REPORTING',
cpu_p1 => 50 -- Allocate 50% CPU to reporting group
);
END;
/
4.5 Updating Statistics
Stale statistics can lead to CPU-intensive plans.
Example:
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'ORDERS');
Real-Life Scenario: Updating statistics on the ORDERS table reduced CPU usage by 30% by enabling the optimizer to choose an index scan over a full table scan.
Best Practice: Schedule statistics updates during low-usage periods.
Step 5: Advanced Troubleshooting Techniques
For persistent CPU issues, consider these advanced approaches:
5.1 SQL Tuning Advisor
Oracle’s SQL Tuning Advisor analyzes queries and suggests optimizations.
Example:
BEGIN
DBMS_SQLTUNE.CREATE_TUNING_TASK(
sql_id => 'xyz789',
task_name => 'TUNE_ORDER_REPORT'
);
DBMS_SQLTUNE.EXECUTE_TUNING_TASK('TUNE_ORDER_REPORT');
DBMS_SQLTUNE.REPORT_TUNING_TASK('TUNE_ORDER_REPORT');
END;
/
Pros:
Automated index and profile recommendations.
Integrates with Oracle’s optimizer.
Cons:
Requires Tuning Pack license.
May suggest overly complex solutions.
5.2 Parallel Execution
Distribute CPU-intensive queries across multiple cores.
Example:
SELECT /*+ PARALLEL(o, 4) */ order_id
FROM orders o
WHERE order_date > SYSDATE - 30;
Pros:
Reduces CPU load per core.
Speeds up large queries.
Cons:
Can increase overall CPU usage.
Not suitable for all queries.
Best Practice: Test parallel execution in a non-production environment first.
5.3 Database Configuration
Adjust parameters like CPU_COUNT or PARALLEL_MAX_SERVERS to manage CPU allocation.
Example:
ALTER SYSTEM SET parallel_max_servers = 16;
Step 6: Monitoring and Maintenance
Ongoing monitoring prevents CPU usage spikes:
Use OEM: Oracle Enterprise Manager for real-time CPU alerts.
Custom Scripts: Schedule queries to track V$SYSSTAT and V$OSSTAT.
Regular Audits: Review top CPU-consuming queries weekly.
Example Monitoring Script:
SELECT
sql_id,
sql_text,
cpu_time / 1000000 AS avg_cpu_seconds
FROM
v$sql
WHERE
executions > 100
AND cpu_time / executions > 1000000 -- Average CPU > 1 second
ORDER BY
cpu_time / executions DESC;
Pros and Cons of Troubleshooting Techniques
Technique | Pros | Cons |
---|---|---|
Indexing | Reduces CPU via fewer reads | Increases storage and DML overhead |
Query Optimization | No additional resources needed | Requires SQL expertise |
Bind Variables | Reduces parsing CPU usage | May need application changes |
Resource Manager | Controls CPU allocation | Complex to configure |
Statistics Updates | Improves optimizer decisions | Maintenance overhead |
Best Practices and Standards
Monitor Proactively: Set up alerts for CPU usage exceeding 80%.
Optimize First: Focus on query tuning before adding hardware.
Use Bind Variables: Minimize hard parsing in high-concurrency systems.
Test Changes: Validate optimizations in a test environment.
Document Fixes: Log all changes for future reference.
Real-Life Case Study
Scenario: An inventory management system experiences high CPU usage during daily reports, causing delays. Using V$SQL, the DBA identifies a query (sql_id = 'xyz789') consuming 15 CPU seconds per execution.
Actions:
Added an index on order_date.
Rewrote the query to use bind variables.
Updated table statistics.
Configured Resource Manager to limit reporting sessions.
Result: CPU usage dropped by 50%, and report generation time fell from 20 seconds to 5 seconds.
Conclusion
High CPU usage in Oracle Database can stem from inefficient queries, parsing overhead, or resource contention. By systematically monitoring with V$SYSSTAT, V$SQL, and AWR, analyzing execution plans, and applying optimizations like indexing, query rewriting, and Resource Manager, you can restore performance. Regular monitoring and adherence to best practices ensure long-term stability. Start by running the V$SQL query on your database to identify CPU hogs and share your results in the comments!
No comments:
Post a Comment
Thanks for your valuable comment...........
Md. Mominul Islam