Practice 16 - Improving Performance Through Cursor Sharing
Practice 16 - Improving Performance Through Cursor Sharing
Practice 16
Practice Target
In this practice, you will perform the following:
• Demonstrate the behavior of the optimizer when dealing with the literals, variables, and
shared cursors.
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |2
2. Create a script named as display_cursors.sql and insert the following code in it.
vi display_cursors.sql
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |3
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |4
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |5
13. Execute the following code to create a table named as CUSTOMERS2, create an index on
CUSTOMERS2.NLS_LANGUAGE, and gather statistics on them.
-- drop the table, if it exists
DROP TABLE SOE.CUSTOMERS2;
-- 'd' value is of high cardinality, but the rest are of low cardinality
CREATE TABLE SOE.CUSTOMERS2 AS SELECT * FROM SOE.CUSTOMERS WHERE NLS_LANGUAGE IN
('d','XD','PH','LY','SQ');
ALTER TABLE SOE.CUSTOMERS2 ADD PRIMARY KEY (CUSTOMER_ID);
CREATE INDEX SOE.CUSTOMERS2_NLSL_IX ON SOE.CUSTOMERS2(NLS_LANGUAGE) NOLOGGING;
EXEC DBMS_STATS.GATHER_INDEX_STATS('SOE','CUSTOMERS2_NLSL_IX');
14. Execute the following query on the CUSTOMERS2 table using a bind variable.
The value assigned to the query makes the query a low cardinality query.
VARIABLE V_LANG VARCHAR2(4)
exec :V_LANG := 'SQ';
SELECT COUNT(*) FROM SOE.CUSTOMERS2 WHERE NLS_LANGUAGE = :V_LANG;
16. Display the cursors created for the query. Find the value of <sql_id> from the output of the
preceding command.
The optimizer noticed that the query had a predicate that is based on a skewed column. That is
why it marked the cursor as bind-sensitive. When this flag is on, the optimizer monitors the
column cardinality.
define v_sql_id = '<sql_id>'
@display_cursors
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |6
17. Execute the same query with passing a high cardinality value to the bind variable ('d') and
display its execution plan.
Even though such an unselective query would be more efficient with a full table scan or index fast
full scan, the optimizer chooses the same index range scan used for NLS_LANGUAGE='SQ'.
exec :V_LANG := 'd';
SELECT COUNT(*) FROM SOE.CUSTOMERS2 WHERE NLS_LANGUAGE = :V_LANG;
19. Execute the same query again without changing the variable value. Display its execution plan.
This time, the execution plan changed to 'INDEX FAST FULL SCAN' to adapt with the new query
cardinality.
SELECT COUNT(*) FROM SOE.CUSTOMERS2 WHERE NLS_LANGUAGE = :V_LANG;
21. Execute the same query after assigning a low cardinality value to the bind variable ('PH'). Display
the execution plan.
The optimizer picked the best plan for the query, INDEX RANGE SCAN.
exec :V_LANG := 'PH';
SELECT COUNT(*) FROM SOE.CUSTOMERS2 WHERE NLS_LANGUAGE = :V_LANG;
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |7
23. Execute the same query after assigning a new low cardinality value to the bind variable ('LY').
Display the execution plan.
The optimizer used the best access method for this value.
exec :V_LANG := 'LY';
SELECT COUNT(*) FROM SOE.CUSTOMERS2 WHERE NLS_LANGUAGE = :V_LANG;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
25. Execute the same query after assigning the value 'PH' to the bind variable. Display the cursors
afterwards.
Again, cursor number 2 has been used to execute the query.
exec :V_LANG := 'PH';
SELECT COUNT(*) FROM SOE.CUSTOMERS2 WHERE NLS_LANGUAGE = :V_LANG;
@display_cursors
Conclusion
When a query is initially executed, the optimizer is monitoring the values assigned to the bind
variables. It maps out the relationship between the bind values and their appropriate plans. After
this initial period, the executions reach to a steady state where a new bind value results in
picking the best child cursor in the cache, without requiring a hard parse.
26. Cleanup
DROP TABLE CUSTOMERS2;
-- Delete the script file.
host rm display_cursors.sql
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka
Practice 16 - Improving Performance Through Cursor Sharing P a g e |8
Summary
• Executing the same SQL statement with different literals is an inefficient way of writing the SQL
statements.
• Setting CURSOR_SHARING to FORCE could be a temporary solution to the issue of using the literals
in SQL statements.
• When a query is initially executed using bind variables, the optimizer is monitoring the values
assigned to the bind variables. It maps out the relationship between the bind values and their
appropriate plans. After this initial period, the executions reach to a steady state where a new
bind value results in picking the best child cursor in the cache, without requiring a hard parse.
Oracle Database 12c the Ultimate Guide to SQL Tuning, a course by Ahmed Baraka