Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, krishna.

Asked: May 12, 2018 - 5:27 pm UTC

Last updated: May 23, 2018 - 7:53 am UTC

Version: 12

Viewed 1000+ times

You Asked

hi Team,
I am struggling in one of query tunning , below are details assoicated with , please analyse and recommend on it .

SELECT *
FROM   (SELECT
       /*+ INDEX(A INDX14_TABLE1)  INDEX(B IDX51_TABLE2) */
              *
        FROM   TABLE1 A,
               Table2  B 
        WHERE  EXE.process_id = EXT.pin
               AND activity = :"SYS_B_0"
               AND ( status = :"SYS_B_1"
                      OR status IS NULL )
               AND status = :"SYS_B_2"
               AND process = :"SYS_B_3"
               AND ((( zone = :"SYS_B_4" )))
        ORDER  BY process DESC,
                  fork DESC)
WHERE  ROWNUM <= :"SYS_B_5" 


above query does 31K of LIO and due to rownum it brings 10- 12 rows depending upon value in ROWNUM passed , without rownum , total rows are 500~600 returned byt LIO is too high around 30K

For testing pupose i executed query as below :(by removing hint it genrates similar plan )

SELECT
       /*+ INDEX(A INDX14_TABLE1)  INDEX(B IDX51_TABLE2) */
              *
        FROM   TABLE1 A,
               Table2  B 
        WHERE  A.process = b.pin
               AND activity = :"SYS_B_0"
               AND ( status = :"SYS_B_1"
                      OR status IS NULL )
               AND status = :"SYS_B_2"
               AND process = :"SYS_B_3"
               AND ((( zone = :"SYS_B_4" )))
        ORDER  BY process DESC,
                  fork DESC
      
------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                         |      1 |        |      1 |00:00:00.52 |   31088 |       |       |          |
|   1 |  SORT AGGREGATE                       |                         |      1 |      1 |      1 |00:00:00.52 |   31088 |       |       |          |
|*  2 |   HASH JOIN                           |                         |      1 |  30154 |    160 |00:00:00.52 |   31088 |  1106K|  1106K| 2467K (0)|
|   3 |    TABLE ACCESS BY INDEX ROWID BATCHED| TABLE1                  |      1 |  30154 |    594 |00:00:00.01 |     372 |       |       |          |
|*  4 |     INDEX RANGE SCAN                  | INDX14_TABLE1           |      1 |   8898 |    594 |00:00:00.01 |      33 |       |       |          |
|*  5 |    INDEX FAST FULL SCAN               | IDX51_TABLE2            |      1 |    713K|   1075K|00:00:00.40 |   30716 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------------------------------ 


INDX14_TABLE1 index con column : process,activity,status, ( these rows filter nad bring 120 rows from table1
Note : their two colun process and process_id , index used here is having column (process,activity,status)
IDX51_TABLE2: pin ,zone
for column zone data is skew , but histogram will not benefit
my question :
It should execute in nested loop , i am not sure why it is going in HASH join
any futher way to tune it


TABLE2 brings more row , but from table1 rows are around 120 , then it should using nested loop , is something wrong with stats here ??

and Connor said...

What really matters here is how "good" the index on pin,zone is on table2.

Lets say I get 120 rows back from table1 as you say. That means 120 probes into table2. If the IDX51_TABLE2 is nice and selective, than 120 probes might not be expensive. But if the index is not great, then we are multiplying "not great" by 120.

You can test out the performance yourself by using a hint like:

LEADING(a b)
USE_NL_WITH_INDEX(b IDX51_TABLE2)

to force the nested loop from table1 (a) into table2 (b) and do some performance comparisons.

If it *is* indeed better, than look at using an outline or sql plan management to lock in the plan.

If it is *not* better, than you might need to look at alternative/modified index definitions if possible.

Rating

  (3 ratings)

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

Comments

Let oracle do his job

Gh, May 14, 2018 - 7:13 am UTC

Just remove the hints and make sense by removing duplicates AND ( status = :"SYS_B_1" OR status IS NULL ) AND status = :"SYS_B_2"
And make query as it should be eg add missing aliases.
From this point start tuning.

A reader, May 14, 2018 - 8:30 am UTC

Hi Connor,

Thanks for reply , I will check and update on same with hint .

Regards,
Krishna

Krishnaprasad Yadav, May 15, 2018 - 4:36 am UTC

hi Connor , 

Thanks for suggestion .

today i see plan is change below is detials :- 
Execution Plan
----------------------------------------------------------
Plan hash value: 1148949671

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                         |     1 |    98 | 27039   (1)| 00:00:02 |
|   1 |  SORT AGGREGATE                       |                         |     1 |    98 |            |          |
|   2 |   NESTED LOOPS                        |                         |  7736 |   740K| 27039   (1)| 00:00:02 |
|   3 |    TABLE ACCESS BY INDEX ROWID BATCHED| SRV_RU_EXECUTION        |  7736 |   377K| 11533   (1)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN                  | INDX14_SRV_RU_EXECUTION | 55345 |       |   165   (5)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN                   | IDX51_RLOAN_EXT         |     1 |    48 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("ACTIVITYID"=TO_NUMBER(:SYS_B_0) AND "LIVESTATUS"=SYS_OP_C2C(:SYS_B_2) AND
              "PROCESSID"=TO_NUMBER(:SYS_B_3))
       filter("LIVESTATUS"=SYS_OP_C2C(:SYS_B_1))
   5 - access("EXE"."PROCESSINSTANCEID"="EXT"."PINSTID" AND "ZONE"=SYS_OP_C2C(:SYS_B_4))


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      30833  consistent gets
       9800  physical reads
          0  redo size
        543  bytes sent via SQL*Net to client
        552  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


however , i used your suggestion and executed it 

Execution Plan
----------------------------------------------------------
Plan hash value: 1148949671

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                         |     1 |    98 | 27039   (1)| 00:00:02 |
|   1 |  SORT AGGREGATE                       |                         |     1 |    98 |            |          |
|   2 |   NESTED LOOPS                        |                         |  7736 |   740K| 27039   (1)| 00:00:02 |
|   3 |    TABLE ACCESS BY INDEX ROWID BATCHED| SRV_RU_EXECUTION        |  7736 |   377K| 11533   (1)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN                  | INDX14_SRV_RU_EXECUTION | 55345 |       |   165   (5)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN                   | IDX51_RLOAN_EXT         |     1 |    48 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("ACTIVITYID"=TO_NUMBER(:SYS_B_0) AND "LIVESTATUS"=SYS_OP_C2C(:SYS_B_2) AND
              "PROCESSID"=TO_NUMBER(:SYS_B_3))
       filter("LIVESTATUS"=SYS_OP_C2C(:SYS_B_1))
   5 - access("EXE"."PROCESSINSTANCEID"="EXT"."PINSTID" AND "ZONE"=SYS_OP_C2C(:SYS_B_4))


Statistics
----------------------------------------------------------
          7  recursive calls
          0  db block gets
       2332  consistent gets
          0  physical reads 
          0  redo size
        543  bytes sent via SQL*Net to client
        552  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed



Plan hash value is same but consistent get is reduced .
Note here i have used same bind values .

Please suggest is this difference  is due to "use_nl_with_indexes"  ??? 



Connor McDonald
May 23, 2018 - 7:53 am UTC

Please run each of the SQLs with the gather_plan_statistics hint so we can see the true details, ie:

SELECT /*+ gather_plan_statistics */ *
FROM   (SELECT  
       /*+ INDEX(A INDX14_TABLE1)  INDEX(B IDX51_TABLE2) */ *
        FROM   TABLE1 A,
               Table2  B 
        ...
        ...


and after each one, run:

select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'))

More to Explore

Performance

Get all the information about database performance in the Database Performance guide.