Skip to Main Content
  • Questions
  • Performance differ on Temporary tables

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Haranadh Babu.

Asked: September 15, 2017 - 7:24 am UTC

Last updated: September 15, 2017 - 10:40 am UTC

Version: 11.2.0.3

Viewed 1000+ times

You Asked

Please observe my queries explain plan and let me know what is the root cause taking more time on second execution.

--GT Table creation
create global temporary table gt_table1
(column1 varchar2(4000),
column2 varchar2(4000),
...........
...........
...........
column32 varchar2(4000));

--Index creation on GT Table
create index gt_ind on gt_table1(column1);

--Inserted few records in GT Table

First time execution:
---------------------
SELECT DISTINCT L.column1
  FROM table_1 l, table_2 C
 WHERE L.column1 IS NOT NULL
   AND C.column1 = 'N'
   AND L.column2= C.column2
   AND L.column3 = Nvl(C.column4, C.column3)
   AND EXISTS (SELECT 1
          FROM gt_table1 Gt
         WHERE Gt.column1 = 'INV'
           AND Gt.column3 = L.column3
           AND Gt.column2 = L.column2);

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.24       0.24          0      56144          0           7
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.25       0.25          0      56144          0           7

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 100  
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         7          7          7  HASH UNIQUE (cr=56144 pr=0 pw=0 time=243533 us cost=12 size=107 card=1)
     53217      53217      53217   NESTED LOOPS  (cr=56144 pr=0 pw=0 time=175098 us cost=11 size=107 card=1)
       470        470        470    NESTED LOOPS  (cr=45879 pr=0 pw=0 time=885698 us cost=2 size=98 card=1)
     40526      40526      40526     SORT UNIQUE (cr=1678 pr=0 pw=0 time=112705 us cost=1 size=88 card=1)
     43589      43589      43589      TABLE ACCESS BY INDEX ROWID gt_table1 (cr=1678 pr=0 pw=0 time=58867 us cost=1 size=88 card=1)
     43589      43589      43589       INDEX RANGE SCAN gt_ind (cr=468 pr=0 pw=0 time=17695 us cost=1 size=0 card=1)(object id 106265)
       470        470        470     TABLE ACCESS BY INDEX ROWID table_1 (cr=44201 pr=0 pw=0 time=66366 us cost=0 size=10 card=1)
     40526      40526      40526      INDEX UNIQUE SCAN L_PK (cr=2227 pr=0 pw=0 time=26789 us cost=0 size=0 card=1)(object id 106833)
     53217      53217      53217    TABLE ACCESS BY INDEX ROWID table_2 (cr=10265 pr=0 pw=0 time=66445 us cost=9 size=63 card=7)
     53217      53217      53217     INDEX RANGE SCAN FN_L (cr=412 pr=0 pw=0 time=14934 us cost=1 size=0 card=40)(object id 107181)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       2        0.00          0.00
  SQL*Net message from client                     2        0.00          0.00
********************************************************************************

Second time execution:
----------------------
SELECT DISTINCT L.column1
  FROM table_1 l, table_2 C
 WHERE L.column1 IS NOT NULL
   AND C.column1 = 'N'
   AND L.column2= C.column2
   AND L.column3 = Nvl(C.column4, C.column3)
   AND EXISTS (SELECT 1
          FROM gt_table1 Gt
         WHERE Gt.column1 = 'INV'
           AND Gt.column3 = L.column3
           AND Gt.column2 = L.column2);


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.02          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1     32.18      32.19          0    2615299          1           7
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3     32.19      32.21          0    2615299          1           7

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 100  
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         7          7          7  HASH UNIQUE (cr=2615299 pr=0 pw=0 time=32194380 us cost=496 size=107 card=1)
     53217      53217      53217   NESTED LOOPS  (cr=2615299 pr=0 pw=0 time=18648158 us cost=495 size=107 card=1)
       470        470        470    NESTED LOOPS SEMI (cr=2604882 pr=0 pw=0 time=18493280 us cost=486 size=98 card=1)
      2082       2082       2082     TABLE ACCESS FULL table_1 (cr=1774 pr=0 pw=0 time=12285 us cost=486 size=20770 card=2077)
       470        470        470     TABLE ACCESS BY INDEX ROWID gt_table1 (cr=2603108 pr=0 pw=0 time=32121867 us cost=0 size=88 card=1)
  77602103   77602103   77602103      INDEX RANGE SCAN gt_ind(cr=449669 pr=0 pw=0 time=14391938 us cost=0 size=0 card=1)(object id 106265)
     53217      53217      53217    TABLE ACCESS BY INDEX ROWID table_2 (cr=10417 pr=0 pw=0 time=68857 us cost=9 size=63 card=7)
     53217      53217      53217     INDEX RANGE SCAN FN_L (cr=592 pr=0 pw=0 time=16834 us cost=1 size=0 card=40)(object id 107181)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       2        0.00          0.00
  SQL*Net message from client                     2        0.00          0.00
********************************************************************************


and Chris said...

In your second execution, pretty much all the time is spent on these steps:

       470        470        470     TABLE ACCESS BY INDEX ROWID gt_table1 (cr=2603108 pr=0 pw=0 time=32121867 us cost=0 size=88 card=1)
  77602103   77602103   77602103      INDEX RANGE SCAN gt_ind(cr=449669 pr=0 pw=0 time=14391938 us cost=0 size=0 card=1)(object id 106265)


You can see this in the time stat:

 time=32121867 us = 32.1 seconds<code>

Why? 

Well it processes 77 million rows! 77,602,103 to be precise. That's a lot of work...

But it chucks most of these away to end up with just 470!

You can see this in the first three columns "Rows" columns of the plan.

So how can Oracle Database get it so wrong? 

Well it thinks that you'll only access one row from the GTT!

You can see this from the "card=1" stat at the end of the lines accessing g_table1 and g_ind. This is clearly way off.

To overcome this you could try adding the dynamic_sampling hint to your query. e.g.:

<code>SELECT /*+ dynamic_sampling (4) */DISTINCT L.column1
  FROM ...


This may help the optimizer figure out more accurate row estimates for the GTT.

Or you could improve the stats for the GTT by capturing them when it's "full" or setting them manually.

I'd also review that index on the GTT. According to the first plan, you access 43,589 rows using it:

     43589      43589      43589      TABLE ACCESS BY INDEX ROWID gt_table1 (cr=1678 pr=0 pw=0 time=58867 us cost=1 size=88 card=1)
     43589      43589      43589       INDEX RANGE SCAN gt_ind (cr=468 pr=0 pw=0 time=17695 us cost=1 size=0 card=1)(object id 106265)


That seems a little high for it to be effective. Though it depends on how many rows there are in the table...

In any case, you may get some benefit by including the other columns you query in it:

create index gt_ind on gt_table1(column1, column2, column3);


Though you'll need to experiment with this to see if it helps. You may even be better off removing the index completely.

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

More to Explore

Administration

Need more information on Administration? Check out the Administrators guide for the Oracle Database