Find statements that do not use bind variables

 Using different sql statement where only some parameters differs (also known as not using bind variables) is know as the worst performance issue in OLTP.

The reason is that each statement must be parsed, and
- parsing is a high CPU consuming operation
- parsing is a non scalable operation as concurrent parses will wait on shared resources (library cache latches)
- each statement takes an amount of shared pool memory to store same information, so the library cache efficiency is decreased.

As an analogy for developers, this is like having a program with its parameters hardcoded, and compiling it each time it needs to be executed with different parameters - instead of having one program that is compiled once and accepts parameters as arguments.

The solution for that is to use bind variables: a generic statement with bind variables is prepared (parsed) once and then can be executed several times with different values.

This script helps to quickly identify those badly written queries that are different statements, have the same execution plan, where only literals changes.

It shows one of those similar statements in order to identify it, as well as the number of additional resources caused by not having bind variables:
NUMBER_OF_STATEMENTS_OVERHEAD: the number of additional statements
HARD_PARSES_OVERHEAD: the number of additional hard parses
MBYTES_OVERHEAD: the amount of additional shared memory
This statistics help to evaluate the impact of the queries.

The quick and dirty solution for that is to set CURSOR_SHARING=SIMILAR, but it has a lot of drawbacks.
The real solution is to use static statements with bind variables instead of dynamic sql statements with literals.

The script uses the 10g 'force_matching_signature' in v$sql (that is used by cursor_sharing=exact)

In order to show an output example, here is a pl/sql loop that generates 100000 dynamic sql statements with a random value literals:

SQL> begin

     2        for d in 1..100000 loop

    3             execute immediate 'select * from dept join emp using(deptno) where deptno='||(round(10000*dbms_random.value));

    4         end loop;

    5      end;

    6      /

PL/SQL procedure successfully completed.

Then here is the output:

SQL> select

    2    count(*)-1 number_of_statements_overhead,

    3    sum(loads)-max(loads) hard_parses_overhead,

    4    round((sum(sharable_mem)-max(sharable_mem))/1024/1024,3) mbytes_overhead,

    5    max(sql_text) sql_text_for_one_statement,force_matching_signature

    6    from v$sqlarea where force_matching_signature<>0

    7    group by force_matching_signature,plan_hash_value,optimizer_env_hash_value

    8    having count(*) > 1 order by count(*) desc

    9    /

NUMBER_OF_STATEMENTS_OVERHEAD   HARD_PARSES_OVERHEAD    MBYTES_OVERHEAD   SQL_TEXT_FOR_ONE_STATEMENT

------------------------------------------------------         -----------------------------------------    -----------------------------    ------------------------------------------------------------------------------------

                                                              4259                                                       8284                              85,327     select * from dept join emp using(deptno) where deptno=9999

Here we have one statement, and see that there is 4259 statements that differ only by literals.

Those statements have been hard parsed 8284 times (more hard parse than the number of statements means that they have been out of the library cache, and reloaded)

發佈了43 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章