0% found this document useful (0 votes)
31 views8 pages

Practice 16 - Improving Performance Through Cursor Sharing

The document discusses improving performance through cursor sharing in Oracle Database. It demonstrates how using literals can negatively impact performance compared to bind variables. It also shows how setting CURSOR_SHARING to FORCE can help performance but does not always provide optimal plans. The document then demonstrates Oracle's adaptive cursor sharing feature which can create different plans for queries based on bind variable values.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views8 pages

Practice 16 - Improving Performance Through Cursor Sharing

The document discusses improving performance through cursor sharing in Oracle Database. It demonstrates how using literals can negatively impact performance compared to bind variables. It also shows how setting CURSOR_SHARING to FORCE can help performance but does not always provide optimal plans. The document then demonstrates Oracle's adaptive cursor sharing feature which can create different plans for queries based on bind variable values.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

Practice 16 - Improving Performance Through Cursor Sharing P a g e |1

Practice 16

Improving Performance Through Cursor Sharing

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.

• Study the impact of setting CURSOR_SHARING to FORCE

• Demonstrate the mechanism of Adaptive Cursor Sharing feature.

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

Preparing for the Practice


In the following steps, you will create the scripts that will be used in this practice.

1. Start Putty, login to srv1 as oracle

2. Create a script named as display_cursors.sql and insert the following code in it.

vi display_cursors.sql

COL BIND_AWARE FORMAT a10


COL SQL_TEXT FORMAT a22
COL CHILD# FORMAT 99999
COL EXEC FORMAT 9999
COL BUFF_GETS FORMAT 999999999
COL BIND_SENS FORMAT a9
COL SHARABLE FORMAT a9
SELECT 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 SHARABLE
FROM V$SQL
WHERE SQL_ID='&v_sql_id'
ORDER BY CHILD_NUMBER;

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

Literals, Bind Variables and Cursor Sharing


In the following steps, you will examine the behavior of the optimizer when dealing with literals,
variables, and shared cursors.

3. Invoke SQL*Plus and login as soe to ORADB.


sqlplus soe/soe

4. Execute the following queries that use literals in their predicates.


SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') ='01-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') ='02-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') ='03-2010';

5. Retrieve the parent cursors created for the queries.


The three statements require three different parent cursors. VERSION_COUNT indicates that each
parent cursor has a single child cursor.
This demonstrates how using literals develop performance issue. Each statement with different
literal has its own parent cursor.
COL SQL_TEXT FORMAT a30
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%my query%' AND SQL_TEXT NOT LIKE '%SQL_TEXT%';

6. Run the same three queries using bind variables.


ALTER SYSTEM FLUSH SHARED_POOL;
VARIABLE month_year VARCHAR2(7)
EXEC :month_year := '01-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') =:month_year;
EXEC :month_year := '02-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') =:month_year;
EXEC :month_year := '03-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') =:month_year;

7. Retrieve the parent cursor created for the queries.


Only one parent cursor created for the three queries. Having VERSION_COUNT equals to one
means that only one child cursor has been re-used.
COL SQL_TEXT FORMAT a30
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%my query%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%';

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

Demonstrating the Impact of setting CURSOR_SHARING to


FORCE
In Oracle Database 12c, the parameter CURSOR_SHARING supports the values: EXACT (default) and
FORCE. SIMILAR value is deprecated. In the following steps, you will study the impact of setting the
parameter to FORCE.

8. Flush the shared pool.


ALTER SYSTEM FLUSH SHARED_POOL;

9. Set the CURSOR_SHARING parameter to FORCE at the session level.


ALTER SESSION SET CURSOR_SHARING=FORCE;

10. Execute the following three literal-based queries:


SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') ='01-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') ='02-2010';
SELECT /* my query */ TO_CHAR(SUM(ORDER_TOTAL),'999,999,999') TOTAL FROM
SOE.ORDERS WHERE TO_CHAR(ORDER_DATE,'MM-RRRR') ='03-2010';

11. Retrieve the cursors created for the queries.


Oracle replaced the literals with system bind variable, and created one parent and one child
cursor (VERSION_COUNT=1) for all the three statements. This means all the queries shared the
same plan. This does not always provide the optimal execution plan for all the queries.
col SQL_TEXT format a30
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%my query%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%';

12. Re-connect to the SQL*Plus session to reset the session settings.


conn soe/soe

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

Demonstrating Adaptive Cursor Sharing Lifecycle


The adaptive cursor sharing is a mechanism that makes the optimizer create different execution plans
for the bind variable-based queries depending on the bind variable values. In the following steps, you
will demonstrate how this mechanism works. You will execute the same bind variable-based query
several times with passing different values to its bind variable. You will check the created cursors as a
result of passing those values.

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');

-- create histogram on NLS_LANGUAGE column


exec DBMS_STATS.GATHER_TABLE_STATS ( OWNNAME => 'SOE', TABNAME => 'CUSTOMERS2',
METHOD_OPT => 'FOR COLUMNS NLS_LANGUAGE');
ALTER SYSTEM FLUSH SHARED_POOL;

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;

15. Display the execution plan of the preceding query.


The optimizer uses INDEX RANGE SCAN, just as expected for such a low-cardinality query.
SET LINESIZE 180
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

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;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

18. Display the query cursors.


The output shows that the child cursor has now been executed twice.
However, the optimizer monitored the query execution and realized that the new bind variable
('d') caused the queries to differ significantly in its cardinality. It records that value and its
corresponding cardinality in the statement signature.
@display_cursors

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;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

20. Display the query cursors.


The database created an additional child cursor (of number 1). Cursor 0 is now marked as not
shareable, which means the optimizer will not use it any more for executing the query. Cursor 1
shows a number of buffers gets lower than cursor number 0, and is marked both bind-sensitive
and bind-aware.
When the bind-aware flag is set, the optimizer realizes that the execution plan may need to
change based on the bind variable value.
In our example, the access method used in cursor 1 is 'INDEX FAST FULL SCAN', which is used
for high cardinality query.
@display_cursors

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;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

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

22. Display the query cursors.


An additional cursor has been created, cursor child number 2.
­ Child number 1 is used for executing high-cardinality queries. Based on its experience, the
optimizer knows that the predicate NLS_LANGUAGE='d' is of high cardinality and, when it is
used in the query, cursor number 1 should be used to execute the query.
­ Child number 2 is used for executing low-cardinality queries. The optimizer records that if
the variable value is 'PH', this cursor should be used to execute the query.
@display_cursors

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);

24. Display the query cursors.


Observe that the column "EXEC" is incremented for cursor number 2, which means it has been
used for executing the query.
@display_cursors

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

You might also like