Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Doing a query with string vs bind variables.

Re: Doing a query with string vs bind variables.

From: Charles Hooper <hooperc2000_at_yahoo.com>
Date: Tue, 18 Sep 2007 04:21:24 -0700
Message-ID: <1190114484.584169.77780@n39g2000hsh.googlegroups.com>


On Sep 17, 4:42 pm, Luch <DarthL..._at_gmail.com> wrote:

> We have a PowerBuilder application where we started noticing the
> performance of a query is worse if you do it with bind variables then
> if you do the same query as a string. We made a small example and sent
> to Sybase (makers of PB). We noticed that the bind variables query
> will not use the same index as the string query, even though the two
> queries are exactly the same.
>
> Example
>
> String query:
>   SELECT DISTINCT  "ORDER_HEADER"."ORDER_TYPE" ,
> "ORDER_HEADER"."ORDER_NUMBER" ,
> "RELATION_MASTER"."NAME" ,
> "ORDER_HEADER"."RELATION_CODE" ,
> "ORDER_HEADER"."WO" ,
> "ORDER_HEADER"."SHIPPED_FROM_LOCATION" ,
> "ORDER_HEADER"."AUTHORIZATION" ,
> "ORDER_HEADER"."ACCESS_CONTROL" ,
> "ORDER_HEADER"."RELEASE_FOR_AUTHORIZATION" ,
> "ORDER_HEADER"."TOTAL_COST" ,
> "ORDER_HEADER"."CURRENCY" ,           "ORDER_HEADER"."PRIORITY"
> FROM "ORDER_HEADER" ,           "RELATION_MASTER"     WHERE
> ( "ORDER_HEADER"."RELATION_CODE" =
> "RELATION_MASTER"."RELATION_CODE" (+)) and
> ( ( "ORDER_HEADER"."STATUS" = 'OPEN' ) and
> ("ORDER_HEADER"."ACCESS_CONTROL" = 'ADM' or
> ( "ORDER_HEADER"."ACCESS_CONTROL" = 'ALL') ) and
> ( "ORDER_HEADER"."ORDER_TYPE" = 'RO' ) )
>
> Bind variable query:
>   SELECT DISTINCT  "ORDER_HEADER"."ORDER_TYPE" ,
> "ORDER_HEADER"."ORDER_NUMBER" ,
> "RELATION_MASTER"."NAME" ,
> "ORDER_HEADER"."RELATION_CODE" ,
> "ORDER_HEADER"."WO" ,
> "ORDER_HEADER"."SHIPPED_FROM_LOCATION" ,
> "ORDER_HEADER"."AUTHORIZATION" ,
> "ORDER_HEADER"."ACCESS_CONTROL" ,
> "ORDER_HEADER"."RELEASE_FOR_AUTHORIZATION" ,
> "ORDER_HEADER"."TOTAL_COST" ,
> "ORDER_HEADER"."CURRENCY" ,           "ORDER_HEADER"."PRIORITY"
> FROM "ORDER_HEADER" ,           "RELATION_MASTER"     WHERE
> ( "ORDER_HEADER"."RELATION_CODE" =
> "RELATION_MASTER"."RELATION_CODE" (+)) and
> ( ( "ORDER_HEADER"."STATUS" = 'OPEN' ) and
> ("ORDER_HEADER"."ACCESS_CONTROL" = :s_user or
> ( "ORDER_HEADER"."ACCESS_CONTROL" = 'ALL') ) and
> ( "ORDER_HEADER"."ORDER_TYPE" = :s_order_type ) )
>
> In the Bind-variable query, we pass the same parameters as we are hard-
> coding in the equivalent string version.
>
> Why would the bind variable query use a different index, and why it
> would it be a "worse" index then the one the string-query uses?
>
> The puzzling part is that if I take the Bind-variable query and run it
> in Oracle SQL Developer (it will prompt me for the values when run) it
> will also perform well... It is only in running through Sybase
> PowerBuilder that the bind-variable query runs slow. Sybase stated
> they have no control over which index the database will use.
>
> Another note... the above example is only one case... this same
> situation is happening with many queries throughout our application.
>
> any thoughts?

Let's take a look at what you posted (slightly reformatted): The fast query:
SELECT DISTINCT
"ORDER_HEADER"."ORDER_TYPE",
"ORDER_HEADER"."ORDER_NUMBER",
"RELATION_MASTER"."NAME",
"ORDER_HEADER"."RELATION_CODE",
"ORDER_HEADER"."WO",
"ORDER_HEADER"."SHIPPED_FROM_LOCATION",
"ORDER_HEADER"."AUTHORIZATION",
"ORDER_HEADER"."ACCESS_CONTROL",
"ORDER_HEADER"."RELEASE_FOR_AUTHORIZATION",
"ORDER_HEADER"."TOTAL_COST",
"ORDER_HEADER"."CURRENCY",
"ORDER_HEADER"."PRIORITY"

FROM
"ORDER_HEADER",
"RELATION_MASTER"

WHERE
  ("ORDER_HEADER"."RELATION_CODE" =
"RELATION_MASTER"."RELATION_CODE" (+))
  and
   (
    ( "ORDER_HEADER"."STATUS" = 'OPEN' )     and (

      "ORDER_HEADER"."ACCESS_CONTROL" = 'ADM'
      or ( "ORDER_HEADER"."ACCESS_CONTROL" = 'ALL')
        )

    and ( "ORDER_HEADER"."ORDER_TYPE" = 'RO' )    )

The explain plan, the best that I could make out from what you posted: HASH [UNIQUE]

 NESTED LOOPS [OUTER]                                 Est. Cost
Rows Est. KBytes
  INLIST ITERATOR
   ODB_PB.ORDER_HEADER TABLE ACCESS [BY INDEX ROWID]      5
1       0.048
    ODB_PB.I_ORDER_HEADER_1 INDEX [RANGE SCAN]            4
1       --
  ODB_PB.RELATION_MASTER TABLE ACCESS [BY INDEX ROWID]    2
1       0.026
   ODB_PB.I_RELATION_MASTER_CODE INDEX [RANGE SCAN]       1
1       --

Note the INLIST ITERATOR, which is likely the result of Oracle transforming (ORDER_HEADER"."ACCESS_CONTROL" = 'ADM' or "ORDER_HEADER"."ACCESS_CONTROL" = 'ALL') into ORDER_HEADER.ACCESS_CONTROL IN ('ADM','ALL'). It is hard to tell without a DBMS_XPLAN output, but this step is keeping those rows that do no have ACCESS_CONTROL set to 'ADM' or 'ALL' from hitting the NESTED LOOPS operation, while in the SQL statement with the bind variables, the INLIST ITERATOR is not present, which may mean that those rows are filtered after the NESTED LOOPS operation. From a performance standpoint, it is best to eliminate as many rows as possible as early as possible.

The slow query:
SELECT DISTINCT
"ORDER_HEADER"."ORDER_TYPE",
"ORDER_HEADER"."ORDER_NUMBER",
"RELATION_MASTER"."NAME",
"ORDER_HEADER"."RELATION_CODE",
"ORDER_HEADER"."WO",
"ORDER_HEADER"."SHIPPED_FROM_LOCATION",
"ORDER_HEADER"."AUTHORIZATION",
"ORDER_HEADER"."ACCESS_CONTROL",
"ORDER_HEADER"."RELEASE_FOR_AUTHORIZATION",
"ORDER_HEADER"."TOTAL_COST",
"ORDER_HEADER"."CURRENCY",
"ORDER_HEADER"."PRIORITY"

FROM
"ORDER_HEADER" ,
"RELATION_MASTER"

WHERE
  ("ORDER_HEADER"."RELATION_CODE" =
"RELATION_MASTER"."RELATION_CODE" (+))
  and
   (
    ( "ORDER_HEADER"."STATUS" = 'OPEN' )     and (

      "ORDER_HEADER"."ACCESS_CONTROL" = :s_user
      or ( "ORDER_HEADER"."ACCESS_CONTROL" = 'ALL')
        )

    and ( "ORDER_HEADER"."ORDER_TYPE" = :s_order_type )    )

HASH [UNIQUE]

 NESTED LOOPS [OUTER]                               Est. Cost  Rows
Est. KBytes
  ODB_PB.ORDER_HEADER TABLE ACCESS [BY INDEX ROWID]      4
1       0.048
   ODB_PB.I_ORDER_HEADER_CUSTOMER_PO INDEX [RANGE SCAN]  3
1       --
  ODB_PB.RELATION_MASTER TABLE ACCESS [BY INDEX ROWID]   2
1       0.026
   ODB_PB.I_RELATION_MASTER_CODE INDEX [RANGE SCAN]      1
1       --

Note that the INLIST ITERATOR is not present in the above - Oracle did not transform the query. Try changing the WHERE clause as follows: WHERE
"ORDER_HEADER"."RELATION_CODE" =

"RELATION_MASTER"."RELATION_CODE" (+)

  AND "ORDER_HEADER"."STATUS" = 'OPEN'
  AND "ORDER_HEADER"."ACCESS_CONTROL" IN ( :S_USER , 'ALL')
  AND "ORDER_HEADER"."ORDER_TYPE" = :S_ORDER_TYPE

Also, verify that table and index statistics are up to date and try to obtain a DBMS_XPLAN that shows the actual values and predicates, rather than just the estimates (note that the estimates are nearly identical in the above). See:
  http://jonathanlewis.wordpress.com/2006/11/09/dbms_xplan-in-10g/

Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc. Received on Tue Sep 18 2007 - 06:21:24 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US