Take the 2-minute tour ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

I have a general question about something I'm seeing in performance tuning in Oracle. I have a query that I'm testing. It's too big and complex for me to provide a simple example, sorry! (I tried lowering it down, but lost the symptom)

The first time I run the query, it's 2 seconds. Subsequent times it's 3, 4, or even 5 seconds. This happens consistently - if I change the spacing, I get 2 seconds again, then it goes back up.

This is the opposite of what I would expect - after the first time, the database doesn't need to parse the query, and blocks should be in read into the buffer cache. The only thing I can think of is that it is writing temp data somewhere, in such a way that it is faster to write and read it than it is to just read it. But that of course makes no sense.

Does anyone know why this is happening? Or any red flags in the execution plan that would cause something like this?

FYI, this is a SELECT, with multiple joins, aggregation, and views. No internal PL/SQL.

Thank you

@Colin It's unlikely another process could be affecting this Dev machine, at least so consistently. Not sure what dynamic sampling is. Same thing as cardinality feedback?

@druzin No bind variables, but no predicate changes either - same hash.

@mustaccio Good idea, although I suspect it's something to do with implicit temp tables or caching. I'll give it a try.

share|improve this question
    
Are there other processes running on the machine? I wonder if the query takes so many resources that the process of running the query destroys the cache which is built up by other processes' queries. –  Colin 't Hart Sep 26 '13 at 18:33
    
Is the query using dynamic sampling and other means to arrive at execution plans other than just the tables' statistics? –  Colin 't Hart Sep 26 '13 at 18:34
    
Are you using bind variables in your query ? –  druzin Sep 26 '13 at 19:39
    
I guess the first thing to try would be turn autotrace on in SQL*Plus and compare its output for different executions of the query. –  mustaccio Sep 26 '13 at 20:20
    
Does "same hash" mean the same plan_hash_value? How are you generating the plan? Are you absolutely certain that you are comparing the plans that are actually used rather than the plans that Oracle expects before executing the query? –  Justin Cave Oct 28 '13 at 20:16

3 Answers 3

Cases like this can usually be solved for certain by enabling trace events 10046 (if you have authority to do so), and run tkprof on the resulting trace files:

alter session set events '10046 trace name context forever, level 8';
select /* try one */ -- add your SQL here and invoke it;
select /* try two */ -- add your same SQL here and invoke it;
show parameter user_dump_destination

Invoke it a few times, and then turn tracing off, log off to ensure the trace files get closed:

alter session set events '10046 trace name context off';
exit;

Then find your trace file, and run tkprof on it, and the output of tkprof will show you execution statistics (logical reads, physical reads, etc). And you can look at the actual trace file if the tkprof output doesn't help.

If that doesn't help, you can enable 10053 event, and enjoy wading through thousands of lines of output; but sometimes you need to do that.

But first things (well easier things) first; do as others suggested; see if table statistics are up to date, optimizer settings, etc. If you are using the exact same criteria each execution, could be the optimizer is "on the border" on plans. I would ensure you have collected system statistics; see the documentation on dbms_stats.gather_system_stats pl/sql.

share|improve this answer

Some things I would look at:

  • Is there any performance difference between CURSOR_SHARING=EXACT and CURSOR_SHARING=FORCE.
  • Look at the wait events for this SQL_ID.

    select
        event,
        time_waited "time_waited(s)",
        case when time_waited = 0 then 
            0
        else
            round(time_waited*100 / sum(time_waited) Over(), 2)
        end "percentage"
    from
        (
            select event, sum(time_waited) time_waited
            from v$active_session_history
            where sql_id = 'SQL_ID'
            group by event
        )
    order by
        time_waited desc;
    
share|improve this answer

Are the two executions using the same plan? Are you sure? autotrace does not always show the actual plan!

Did you try this?

SELECT ... your query...;
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR);

(twice one after another)

I am guessing that the DB chose one plan for the first execution, then based on the run decided to use another one. What happens if you wait some time and then execute the same query again? Does it run fast or slow again?

share|improve this answer
    
This is not an answer. –  Max Vernon Nov 12 '13 at 23:14
    
It is an answer as much as the others. –  David Balažic Nov 13 '13 at 10:38
3  
sorry - I'm not trying to pick on you. I only saw your answer when looking at the review stream - since it poses several questions, it looks to me like it should be a comment on the original post instead of an answer. You are correct the other answers are just as bad. –  Max Vernon Nov 13 '13 at 14:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.