Child Cursors Related with Bind Variables

Child Cursors: BIND_MISMATCH, BIND_LENGTH_UPGRADEABLE and BIND_EQUIV_FAILURE

Bind variables are placeholders in SQL statements that improve performance and enhance security. Instead of generating a new execution plan for each query, the database reuses the same plan for queries with identical structures, differing only in the values of the bind variables. This approach reduces the overhead of parsing and planning while also mitigating risks like SQL injection.

The main advantage of bind variables is their ability to enable cursor sharing in the library cache, reducing hard parses and helping to prevent ORA-4031 errors. However, a disadvantage is that crucial information, such as the actual values of bind variables, is hidden from the query optimizer, which can hinder its ability to generate optimal execution plans, this limitation applies only when the adaptive cursor sharing feature is not utilized which is enabled by default.

When a SQL statement is parsed, the database creates a cursor in the library cache. The cursor stores the parsed SQL statement, execution plan and metadata, which includes information about the bind variables, such as their names, positions and data types. The type and the size of bind variables matter for sharing the cursor.

Sometimes working with bind variables can present challenges, as certain situations may disrupt their intended optimization benefits. This can lead to an excessive number of child cursors being generated for reasons such as BIND_MISMATCH, BIND_LENGTH_UPGRADEABLE, and BIND_EQUIV_FAILURE. In such cases, the _cursor_obsolete_threshold parameter can help manage the situation by limiting the number of child cursors created. By setting this parameter to a lower value (default is 8192 in Oracle Database 19c), the impact can be mitigated until the underlying issue is resolved. For non-CDB environments, 1024 might be a good starting point. Refer to Mike Dietrich’s blog post (Oracle 12.2 and higher: Set _cursor_obsolete_threshold to old default) for more details.

These terms (BIND_MISMATCH, BIND_LENGTH_UPGRADEABLE, and BIND_EQUIV_FAILURE) appear as reasons in the v$sql_shared_cursor view. As of December 2024, in Oracle Database 23ai Edition, there are 64 distinct reasons for creating child cursors. These three reasons can easily be confused with one another, especially since all three involve the term “bind.”

Now I’ll try to explain what they mean, how they differ and provide examples to make them easier to understand.

I will use SH sample schema and SALES table on Oracle Database Version 23.5 running on Docker. You may refer to my blog post for “Install Oracle Database 23ai and Sample Schemas on Macbook M Series (Apple Silicon)” for creating a test environment.

Description : The bind metadata does not match the existing child cursor.

First, I will use a bind variable with a NUMBER type. The column data type is also NUMBER, so no implicit conversion is needed.

I will query the sales data for customers with a customer ID less than 100,000. There are a total of 918,843 sales records, out of which 916,039 sales belong to customers with cust_id lower than 100000 The selectivity for this condition is calculated as 916,039 / 918,843 = 0,996948336114004

Based on this low selectivity, the Cost-Based Optimizer (CBO) is expected to choose an Full Scan for optimal performance.

Second, I will use a bind variable with a VARCHAR2 type, while the column data type is numeric. An implicit conversion will take place, and the optimizer will create a new child cursor since the data type of the bind variable differs from the current available cursors of that sql statement stored in the library cache.

Another child cursor is created which can be observed in v$sql_shared_cursor.

V$SQL_BIND_METADATA describes metadata related to bind variables. Bind metadata provided by the client will be checked from here.

The first query I executed used a bind variable where DATATYPE 2 (NUMBER). This query resulted in the creation of Child Cursor 0, as it was the initial cursor for this query.

For the second query, I used a bind variable with DATATYPE 1 (VARCHAR2), having a maximum length of 32. Since the data type of the bind variable differed from the first query, the database could not reuse the existing cursor. As a result, it created Child Cursor 1 to accommodate this new bind variable type and length.

Description : Bind length(s) required for the current cursor are longer than the bind length(s) used to build the child cursor.

Up to now, I have queried the SH.SALES table using the bind_var variable with data types NUMBER and VARCHAR2(32). This time, I will run the same query but increase the upper limit of the VARCHAR2 data type length to 128.

Bind variables are classified into four size groups based on their length:

  1. Up to 32 bytes
  2. 33 to 128 bytes
  3. 129 to 2,000 bytes
  4. More than 2,000 bytes

When it is checked from the v$sql_bind_metadata:

Now, for the same query, we have three different child cursors. Imagine numerous SQL statements with bind parameters running in the background, each using inconsistent data type definitions or lacking standardized definitions on the application side. This inconsistency can quickly lead to the same SQL statement being associated with a large number of child cursors, significantly impacting both performance and memory usage.

Description: The bind value’s selectivity does not match that used to optimize the existing child cursor.

In the first query, I retrieved the sales data for customers with a customer ID less than 100,000. The Cost-Based Optimizer (CBO) opted for a full table scan, peeking at the bind variable value of 100,000. Now, I will query the sales for customers with a customer ID lower than 3. There are 176 sales for customers with cust_id < 3, resulting in a selectivity of 176/918,843 = 0.000191545236781. In this case, an index scan appears to be a much more feasible decision.

I will execute the query with different bind values, which will result in additional child cursors being created as the predicate selectivity rate varies.

Child cursors:

Sql Plans:

Although there are two feasible execution plans, numerous child cursors are generated, constantly updating their selectivity statistics.

This reason one is by far the most troublesome in these three reasons. Many organizations remain cautious about using the Adaptive Cursor Sharing (ACS) feature. In its early days, the feature was a little bit plagued with bugs that made its behavior unpredictable. If left unchecked or unmanaged, ACS could rapidly consume shared pool memory (ORA-4031) and significantly impact CPU utilization, leading to performance degradation in a short time. When it comes to understanding ACS, Mohamed Houri’s blog stands out as an invaluable resource. I often refer to his insights and advice, as they provide practical solutions and deep technical understanding of ACS. His advice: By default, let Adaptive Cursor Sharing (ACS) and Extended Cursor Sharing (ECS) work without altering any related parameters. However, if performance issues arise, you should be able to identify that ACS is the root cause and solve it at the sql statement level.

To diagnose ACS-related issues, you can use the following query.

If you are not utilizing ACS, the optimizer loses access to valuable bind information. Without ACS, bind peeking occurs only during the first execution, and while the goal is to create a stable execution plan, your database’s performance stability becomes precariously dependent on the bind values of the first statement’s bind parameters.

I will use the example of gender data in the army to explain this. It’s a great illustration of skewed data. If you query information about women in the army, an index scan is optimal due to the smaller dataset. However, for men, a full table scan is more efficient since they form the majority. Now, imagine a critical application screen is first executed with skewed bind values. If the execution plan is decided based on those parameters, overall performance will suffer significantly for subsequent runs with the majority.

Another interesting example comes from Tom Kyte, as explained by Alex Gorbachev in “Oracle Database Administration from the Oak Table” book. This example, which I particularly liked, highlights Adaptive Cursor Sharing (ACS) and introduces the concept of nonsense correlation. It describes how seemingly unrelated factors can impact database performance due to the order of execution and bind variable peeking. When an execution plan is generated using an initial set of skewed bind values, such as values that target a small subset of data and favor an index scan, subsequent queries with different bind values may perform poorly if a full table scan would have been more efficient.

Mrs. Early Bird typically logs into the system early on Mondays and opens the main screen, triggering a key SQL statement that uses bind variables. Due to a weekend database instance bounce, all execution plans are cleared. When Mrs. Early Bird runs the statement first, Oracle’s bind variable peeking optimizes it for fast performance using a nested-loop join with an index range scan.

However, if she’s delayed (e.g., due to heavy Monday rains), a 9 AM report runs first, using different bind variable values better suited for a full table scan and hash join. This causes Oracle to create an inefficient execution plan for subsequent users, leading to performance issues.

The heavy Monday rains and performance problems form a “nonsense correlation,” illustrating how bind variable peeking and the order of SQL execution can impact database performance.

Version_rpt is a function that can be used for investigating child cursors. Script’s latest version is available in the link.

The function generates a summary report from the v$sql_shared_cursor view, providing additional diagnostic details based on the reason code. It counts all versions with a ‘Y’ in any column and identifies those where all columns contain ‘N’. More information is available on High SQL Version Counts – Script to determine reason(s) (Doc ID 438755.1)

Here is the sample report for sql statement (580z1pv8ga9b5)

Not using bind variables is not an option, but inefficient usage can sometimes lead to the creation of additional child cursors. In such cases, the root cause should be investigated, and an appropriate solution must be implemented. The version_rpt tool can also be used for this investigation.

For issues like BIND_MISMATCH or BIND_LENGTH_UPGRADEABLE, modifying the application code usually resolves the problem.

When dealing with child cursors caused by BIND_EQUIV_FAILURE, I first attempt to rewrite the SQL statement, if possible. For Adaptive Cursor Sharing (ACS)-related issues, since they are primarily tied to predicates, rewriting the SQL may not always resolve the problem because the same predicates are involved. In such cases, working with column histograms and extended statistics can also help. However, in most scenarios, the solution ends up with the addition of the /*+ NO_BIND_AWARE */ hint.

Hope it helps.


Discover More from Osman DİNÇ


Comments

Leave your comment