views:

119

answers:

2

We have a .NET application talking to Oracle 10g. Our DBA recently pulled a list of queries where executions is equal to parse_calls. We assumed that this would help us find all of the unparameterized queries in our code.

Unexpectedly, the following query showed up near the top of this list, with 1,436,169 executions and 1,436,151 parses:

SELECT bar.foocolumn
  FROM bartable bar,
       baztable baz
 WHERE bar.some_id = :someId
   AND baz.another_id = :anotherId
   AND baz.some_date BETWEEN bar.start_date AND (nvl(bar.end_date, baz.some_date + (1/84600)) - (1/84600))

Why is executions equal to parse_calls for this query?

+3  A: 

Likely because the .NET programmers have chosen to code a routine like this in pseudocode:

Loop over someId's and anotherId's
  parse(your_query);
  bind someId and anotherId to your_query;
  execute(your_query);
  close(your_query);
end loop;

where they should have coded it like this:

parse(your_query);
Loop over someId's and anotherId's
  bind someId and anotherId to your_query;
  execute(your_query);
end loop;
close(your_query);

Or even better: use a single query to retrieve for all data for all someId's/anotherId's

Regards, Rob.

Rob van Wijk
+1: most likely explanation
Vincent Malgrat
It doesn't look like the .NET code in question is looping around the query in question.We're using System.Data.OracleClient and doing the following:1. build a query string2. add parameters to a command3. execute a reader (yes, it should be ExecuteScaler() since we're expecting a single value back).Would that type of usage line up with the first block of pseudocode above?
Cory Grimster
@Rob - but wouldn't either case result in the SQL being found in the shared pool?
dpbradley
@dpbradley: yes, that's why most parse calls are soft parse calls. But parse calls nonetheless.
Rob van Wijk
@Cory: if there is no loop, then you just execute it very often and you should follow Vincent's advice: cache the cursor and reuse it.
Rob van Wijk
You guys were extremely helpful. If I could have accepted both answers I would have. I definately have some things to look over and discuss with the other developers and our DBA. Thank you!
Cory Grimster
+3  A: 

Hi Cory,

the number of times a query is parsed is entirely dependent upon the calling application. A query will be parsed once each time the application asks the database to parse it.

Server side, there are different kinds of parse:

  • HARD parse -- the query has never been seen before, isn't in the shared pool. We must parse it, hash it, look in the shared pool for it, don't find it, security check it, optimize it, etc (lots of work).

  • SOFT parse -- the query has been seen before, is in the shared pool. We have to parse it, hash it, look in the shared pool for it and find it (less work then a hard parse but work none the less)

Most likely in your case you are creating the statement once per session and then discard it so Oracle has to parse it each time. However, thanks to parameterizing, this parse is a soft one and Oracle only gets to the expensive step of optimizing it once.

Still, you can probably cache the statement in your application and reuse it, so as to (soft) parse it only once per session.

Vincent Malgrat
Ah, that helps, and I think it answers the question I asked in the comments on Rob's answer as well. We are building up the query string, OracleCommand object, etc. each time we run the query.That sounds like it would result in a soft parse each time we execute it.If we hung onto our OracleCommands in an application cache, would that save the parases? Hanging onto database resources in the .NET app doesn't sound good on the face of it. We're always being told to Dispose() database objects as soon as we're done with them.
Cory Grimster
+1 for the good explanation and advice
Rob van Wijk
@Cory: Each time you build a OracleCommand object from a character string the parse counter goes up. Only you can tell if this work is superfluous. It could be a good idea to cache the statements that are most likely to be executed a lot of times afterwards.
Vincent Malgrat
Or you can switch to using PL/SQL instead of .NET, in which case the session cursor cache and the PL/SQL cursor cache takes care of this stuff automatically. I guess that's not an option :-)
Rob van Wijk
@Rob: agreed -- Also in PL/SQL you hardly ever need to build a query from a string :)
Vincent Malgrat