Oracle Sql & Plsql performance Tips
- Satya
- Feb 17
- 3 min read
I'm this blog post I will outline some real time use cases related to performance tuning on oracle sql and plsql. đĄđ»đ
Below are examples demonstrating the best practices for Oracle SQL & PL/SQL performance tuning.
1. SQL Performance Tuning Examples
a. Avoid SELECT *Â and Fetch Only Required Columns
â Bad Practice
SELECT * FROM employees WHERE department_id = 10;
â Optimized Version
SELECT employee_id, first_name, salary FROM employees WHERE department_id = 10;
Why? Fetching only necessary columns reduces memory usage and improves performance.
b. Use EXISTSÂ Instead of IN
â Bad Practice (Subquery with IN)
SELECT * FROM employees WHERE department_id IN (SELECT department_id FROM departments WHERE location_id = 100);
â Optimized Version (EXISTS is usually faster)
SELECT * FROM employees e WHERE EXISTS ( SELECT 1 FROM departments d WHERE d.department_id = e.department_id AND d.location_id = 100 );
Why? EXISTS stops searching as soon as it finds a match, whereas IN may check all rows.
c. Use Proper Indexing
â Creating an Index on Frequently Queried Columns
CREATE INDEX idx_emp_dept ON employees(department_id);
â Using a Composite Index for Multi-Column Queries
CREATE INDEX idx_emp_name_dept ON employees(last_name, department_id);
Why? Indexes speed up lookups but should be used carefully, as too many indexes can slow down INSERT/UPDATE/DELETE.
d. Avoid Functions on Indexed Columns
â Bad Practice (Function on an Indexed Column Prevents Index Usage)
SELECT * FROM employees WHERE UPPER(last_name) = 'SMITH';
â Optimized Version (Function-Based Index)
CREATE INDEX idx_upper_lastname ON employees(UPPER(last_name)); SELECT * FROM employees WHERE UPPER(last_name) = 'SMITH';
Why? Normal indexes donât work when a function is applied to a column, so a function-based index is required.
e. Use UNION ALLÂ Instead of UNION
â Bad Practice (Using UNION unnecessarily)
SELECT first_name FROM employees WHERE department_id = 10 UNION SELECT first_name FROM employees WHERE department_id = 20;
â Optimized Version (UNION ALLÂ is Faster)
SELECT first_name FROM employees WHERE department_id = 10 UNION ALL SELECT first_name FROM employees WHERE department_id = 20;
Why? UNION removes duplicates, which requires sorting. If duplicates are not a concern, UNION ALL is much faster.
f. Analyzing Execution Plan
â Check Execution Plan for Query Performance
EXPLAIN PLAN FOR SELECT FROM employees WHERE department_id = 10; SELECT FROM TABLE(DBMS_XPLAN.DISPLAY);
Why? Helps understand how Oracle processes queries and find bottlenecks.
2. PL/SQL Performance Tuning Examples
a. Use BULK COLLECTÂ Instead of Row-by-Row Fetching
â Bad Practice (Row-by-Row Processing)
DECLARE CURSOR emp_cursor IS SELECT employee_id, salary FROM employees; v_employee_id employees.employee_id%TYPE; v_salary employees.salary%TYPE;
BEGIN
FOR emp_rec IN emp_cursor LOOP -- Process each record one by one DBMS_OUTPUT.PUT_LINE(emp_rec.employee_id || ' - ' || emp_rec.salary);
END LOOP;
END;
â Optimized Version Using BULK COLLECT
DECLARE TYPE emp_table IS TABLE OF employees%ROWTYPE; emp_list emp_table; BEGIN
SELECT * BULK COLLECT INTO emp_list FROM employees; FOR i IN emp_list.FIRST .. emp_list.LAST LOOP DBMS_OUTPUT.PUT_LINE(emp_list(i).employee_id || ' - ' || emp_list(i).salary); END LOOP; END;
Why? BULK COLLECT reduces context switching between PL/SQL and SQL engines, improving performance.
b. Use FORALLÂ Instead of FORÂ Loop for DML Operations
â Bad Practice (Row-by-Row Insert - Slow)
DECLARE
CURSOR emp_cursor IS SELECT employee_id, salary FROM employees;
BEGIN FOR emp_rec IN emp_cursor LOOP INSERT INTO employee_backup VALUES (emp_rec.employee_id, emp_rec.salary); END LOOP;
COMMIT;
END;
â Optimized Version Using FORALL
DECLARE
TYPE emp_table IS TABLE OF employees%ROWTYPE;
emp_list emp_table;
BEGIN
SELECT * BULK COLLECT INTO emp_list FROM employees;
FORALL i IN 1..emp_list.COUNT INSERT INTO employee_backup VALUES emp_list(i); COMMIT;
END;
Why? FORALL performs batch processing, reducing context switching and improving speed.
c. Use PL/SQL Function Result Caching
â Enable Function Result Cache
CREATE OR REPLACE FUNCTION get_employee_name (p_emp_id NUMBER) RETURN VARCHAR2 RESULT_CACHE IS v_name employees.first_name%TYPE;
BEGIN
SELECT first_name INTO v_name FROM employees WHERE employee_id = p_emp_id; RETURN v_name;
END;
Why? The RESULT_CACHE stores function results in memory, reducing repetitive database calls.
3. Database-Level Tuning Examples
a. Gathering Table Statistics
â Update Table Statistics for the Optimizer
EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEES');
Why? Helps Oracleâs optimizer make better execution plan decisions.
b. Monitoring Database Performance with AWR Report
â Generate AWR Report to Analyze Performance Issues
SELECT * FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML(10, 20));
Why? AWR reports help identify slow queries, CPU bottlenecks, and inefficient execution plans.
Final Thoughts
Implementing these best practices can significantly improve the performance of Oracle SQL & PL/SQLÂ workloads.
Hope this helps . Happy learning.
ComentĂĄrios