Skip to Main Content
  • Questions
  • Session level statistics on global temporary tables

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, John.

Asked: May 02, 2019 - 10:32 am UTC

Last updated: May 21, 2019 - 4:04 am UTC

Version: 12.1.0.2

Viewed 10K+ times! This question is

You Asked

I was excited to learn that since 12c we can have session level statistics on global temporary tables. Excellent. However when trying this out, I found there was an implicit commit happening - which wasn't so excellent. So much so - that I raised an idea here ( https://community.oracle.com/ideas/24889 ) to not do that.

However - I have since found that this implicit commit only happens when the GTT is using on commit preserve rows. Unfortunately I need this to happen for other reasons.

create global temporary table JKTST(text varchar2(20));
insert into JKTST values('A row');
exec dbms_stats.gather_table_stats(user,'JKTST');
select count(*) from dba_tab_statistics where table_name = 'JKTST' and scope='SHARED';
rollback;
select * from JKTST;


In the above example, that last select returns no rows - due to the rollback. However if we now create the table like this with on commit preserve rows:

create global temporary table JKTST(text varchar2(20)) on commit preserve rows;
insert into JKTST values('A row');
exec dbms_stats.gather_table_stats(user,'JKTST');
select count(*) from dba_tab_statistics where table_name = 'JKTST' and scope='SHARED';
rollback;
select * from JKTST;


That last select returns the row. Why does on commit preserve rows force an implicit commit in gather stats? Is this a feature or a bug??

On a related topic - does gathering session stats force a subsequent hard-parse every time? I.e. if I gather session stats on a temporary table prior to running a select statement on it, will a hard-parse be done each time I that (gather->execute query) (presuming those stats have changed since the last run)?

Thanks,
John

and Connor said...

I spoke to the Optimizer PM on this one. It is "correct behaviour", the background being:

Up until 12c, every dbms_stats gather call does a commit. That has always been the case. Even with a GTT, because a gather stats is *still* making the those stats available to *all* sessions. But fast forward to the advent of *session* level statistics for GTT's, and now we have the capacity to make those stats available only to the session that populated the table.

So in the code for dbms_stats, there is a routine called (in essence): "should_i_commit?" and here's a cut from the comment section:

-- DESCRIPTION:
  --     This procedure will decide whether the target table is a "on
  --     commit delete rows" GTT with session private stats. If yes,
  --     we do not commit. Otherwise we commit.

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

What is the significance of "On Commit Delete Rows"?

John Keymer, May 13, 2019 - 7:21 am UTC

Thanks Conor,
However - I'm a little confused as to what the significance of the GTT being "On Commit Delete Rows" is? For the purposes of this functionality, why does it matter? If the session does a commit, those rows are only visible to the session anyway, as are the private stats.

-- DESCRIPTION:
  --     This procedure will decide whether the target table is a "on
  --     commit delete rows" GTT with session private stats. If yes,
  --     we do not commit. Otherwise we commit.


Surely that should just be:

-- DESCRIPTION:
  --     This procedure will decide whether the target table is a 
  --     GTT with session private stats. If yes,
  --     we do not commit. Otherwise we commit.


because the persistence of rows on commit should make no difference?
Connor McDonald
May 14, 2019 - 6:31 am UTC

I don't write the comments :-)

My *presumption* is that up until now, it was never of any use to gather states on a 'on commit delete row' global temp table (GTT). The act of doing so would of course result in a row count of zero (both reality and in the statistics) because the commit wipes the table.

Hence *historical* functionality (aka pre private stats), has been:

a) People *might* be gathering stats for GTT on-commit-preserve table, because they wanted stats *even though* they became database-wide statistics.

b) People would be extremely unlikely to be gathering stats on a GTT on-commit-delete table, because it makes no sense to do so.

So armed with that above - along comes session level stats. We want to cater to both (a) and (b) above. If we changed across the board to "gather stats does NOT commit" then we could easily be breaking people's existing code in scenario (a) because their code could be *relying* on the commit in dbms_stats to be taking care of ending the transaction.

Make sense?

John Keymer, May 14, 2019 - 7:15 am UTC

Thanks, yes that makes sense - I personally like to explicitly issue a commit if I want to commit, rather than relying on implicit commits in DDL, but I can see how people may have done otherwise.

Maybe when I'm feeling like a few days of torture, repetition and banging head against a wall, I'll go through support to submit as an enhancement request to make it a parameter to the dbms_stats call. ;)
Connor McDonald
May 21, 2019 - 4:04 am UTC

I too would like dbms_stats to be transactional

More to Explore

Design

New to good database design? Check out Chris Saxon's full fundamentals class.