Home » RDBMS Server » Performance Tuning » How to reduce the consistent gets of this sql (Oracle 10.2.0.4.0 64bit , AIX 5.3)
How to reduce the consistent gets of this sql [message #513370] Mon, 27 June 2011 02:21 Go to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Hi, guys
How can I reduce the consistents gets of the sql:
select b.OFFER_ID,
        b.OFFER_CODE,
        b.OFFER_NAME,
        b.OFFER_COMMENTS,
        b.BAND_ID,
        b.CAN_BE_BUY_ALONE,
        b.PRICING_PLAN_ID,
        b.PRIORITY,
        b.STATE,
        to_char(b.EFF_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.EXP_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.BEGIN_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.END_DATE, 'yyyymmdd hh24:mi:ss'),
        b.REDOFLAG,
        b.MIN_NUM,
        b.MAX_NUM,
        b.EXP_DATE_OFFSET,
        b.EXP_DATE_OFFSET_UNIT,
        b.USER_RANGE,
        b.OFFER_ATTR_TYPE,
        b.OFFER_TYPE,
        to_char(b.STATE_CHG_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.OFFER_CRT_DATE, 'yyyymmdd hh24:mi:ss'),
        b.GROUP_TYPE_ID,
        nvl(b.GROUP_LIMIT_RULE, 0),
        b.PROD_OFFER_PUBLISHER,
        b.CUSTOM_REQUEST,
        b.OPERATION_MODLE,
        a.GROUP_ID,
        a.REGION_NAME,
        c.pricing_desc,
        d.band_name,
        b.eff_type,
        b.exp_type,
        b.MIN_ORDER_NUM,
        b.MAX_ORDER_NUM,
        b.IF_CUST_PRICE
   from REGION a, PRODUCT_OFFER b, PRICING_PLAN c, BAND d
   where a.offer_id = b.Offer_Id
    and b.pricing_plan_id = c.pricing_plan_id
    and b.band_id = d.band_id
    and b.state = 'A'
    and b.Eff_Date < sysdate and
    b.exp_date > sysdate
    and b.begin_date < sysdate
    and b.end_date > sysdate
    and '#10030#10044#200109#218265#' like '%#' || a.group_id || '#%'
    and to_number(a.Right_Limit) <= 0
    --and (a.Chn_Class_Limit like '%#' ||  || '#%' or
        --trim(:channel_segment) is null)
    and 0 = Offer_Login_Limit_Check(b.offer_id,'nf0S01');


Offer_Login_Limit_Check is a function of check the valid user login.

The function definition :
CREATE OR REPLACE FUNCTION OFFER_LOGIN_LIMIT_CHECK
(
  IN_OFFER_ID PRODUCT_OFFER.OFFER_ID%TYPE,
  IS_LOGIN_NO DLOGINMSG.LOGIN_NO%TYPE
) RETURN NUMBER IS
  RETNUM    NUMBER;
  VN_COUNTS NUMBER;
    
BEGIN

  RETNUM    := 0;
  VN_COUNTS  := 0;
 
  IF is_login_no is NULL then
  
    RETURN 0;
    
  END if;

    SELECT   MAX (cnum) INTO VN_COUNTS
      FROM   (SELECT   COUNT (0) cnum
                FROM   SBANDOFFER
               WHERE       ELEMENT_CODE = IS_LOGIN_NO
                       AND ELEMENT_TYPE = 'gh'
                       AND OFFER_ID = IN_OFFER_ID
                       AND BAND_TYPE = 80
                       AND STATE = '1'
                       AND EFFDATE <= SYSDATE
                       AND EXPDATE >= SYSDATE
              UNION
              SELECT   COUNT (0) cnum
                FROM   dloginrolerel a, sbandoffer b
               WHERE       a.login_no = IS_LOGIN_NO
                       AND a.power_code = b.element_code
                       AND element_type = 'js'
                       AND BAND_TYPE = 80
                       AND OFFER_ID = IN_OFFER_ID
                       AND STATE = '1'
                       AND EFFDATE <= SYSDATE
                       AND EXPDATE >= SYSDATE);
                       
      
     IF VN_COUNTS > 0 THEN
        RETNUM := 1;
     END IF;
  
  
  RETURN RETNUM;
  
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN - SQLCODE;
  WHEN OTHERS THEN
    RETURN SQLCODE;
    
END OFFER_LOGIN_LIMIT_CHECK;


The execution plan of the sql:
Execution Plan
----------------------------------------------------------
Plan hash value: 894788602
-----------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                   |   134 | 36314 |   150   (7)| 00:00:02 |
|*  1 |  HASH JOIN                      |                   |   134 | 36314 |   150   (7)| 00:00:02 |
|   2 |   TABLE ACCESS FULL             | BAND              |    55 |   660 |     3   (0)| 00:00:01 |
|*  3 |   HASH JOIN                     |                   |   134 | 34706 |   146   (7)| 00:00:02 |
|   4 |    MERGE JOIN                   |                   |   157 | 34540 |   111   (8)| 00:00:02 |
|*  5 |     TABLE ACCESS BY INDEX ROWID | PRODUCT_OFFER     |   156 | 29016 |    96   (8)| 00:00:02 |
|*  6 |      INDEX FULL SCAN            | PRODUCT_OFFER_IDX |   224 |       |    80   (9)| 00:00:01 |
|*  7 |     SORT JOIN                   |                   |   226 |  7684 |    15   (7)| 00:00:01 |
|*  8 |      TABLE ACCESS BY INDEX ROWID| REGION            |   226 |  7684 |    14   (0)| 00:00:01 |
|*  9 |       INDEX RANGE SCAN          | IDX_REGION_FUN    |   819 |       |     3   (0)| 00:00:01 |
|  10 |    INDEX FAST FULL SCAN         | IDX_REGION_COM_1  | 18191 |   692K|    34   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("B"."BAND_ID"="D"."BAND_ID")
   3 - access("B"."PRICING_PLAN_ID"="C"."PRICING_PLAN_ID")
   5 - filter("B"."STATE"='A' AND "B"."END_DATE">SYSDATE@! AND "B"."EXP_DATE">SYSDATE@! AND
              "B"."EFF_DATE"<SYSDATE@! AND "B"."BEGIN_DATE"<SYSDATE@!)
   6 - filter("OFFER_LOGIN_LIMIT_CHECK"("B"."OFFER_ID",'nf0S01')=0)
   7 - access("A"."OFFER_ID"="B"."OFFER_ID")
       filter("A"."OFFER_ID"="B"."OFFER_ID")
   8 - filter('#10030#10044#200109#218265#' LIKE '%#'||"A"."GROUP_ID"||'#%')
   9 - access(TO_NUMBER("RIGHT_LIMIT")<=0)
Statistics
----------------------------------------------------------
      22524  recursive calls
          0  db block gets
     138064  consistent gets
          0  physical reads
          0  redo size
     264416  bytes sent via SQL*Net to client
       2109  bytes received via SQL*Net from client
        149  SQL*Net roundtrips to/from client
      22525  sorts (memory)
          0  sorts (disk)
       2206  rows processed



The sql trace of this sql:
********************************************************************************

select  b.OFFER_ID,
        b.OFFER_CODE,
        b.OFFER_NAME,
        b.OFFER_COMMENTS,
        b.BAND_ID,
        b.CAN_BE_BUY_ALONE,
        b.PRICING_PLAN_ID,
        b.PRIORITY,
        b.STATE,
        to_char(b.EFF_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.EXP_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.BEGIN_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.END_DATE, 'yyyymmdd hh24:mi:ss'),
        b.REDOFLAG,
        b.MIN_NUM,
        b.MAX_NUM,
        b.EXP_DATE_OFFSET,
        b.EXP_DATE_OFFSET_UNIT,
        b.USER_RANGE,
        b.OFFER_ATTR_TYPE,
        b.OFFER_TYPE,
        to_char(b.STATE_CHG_DATE, 'yyyymmdd hh24:mi:ss'),
        to_char(b.OFFER_CRT_DATE, 'yyyymmdd hh24:mi:ss'),
        b.GROUP_TYPE_ID,
        nvl(b.GROUP_LIMIT_RULE, 0),
        b.PROD_OFFER_PUBLISHER,
        b.CUSTOM_REQUEST,
        b.OPERATION_MODLE,
        a.GROUP_ID,
        a.REGION_NAME,
        c.pricing_desc,
        d.band_name,
        b.eff_type,
        b.exp_type,
        b.MIN_ORDER_NUM,
        b.MAX_ORDER_NUM,
        b.IF_CUST_PRICE
   from REGION a, PRODUCT_OFFER b, PRICING_PLAN c, BAND d
   where a.offer_id = b.Offer_Id
    and b.pricing_plan_id = c.pricing_plan_id
    and b.band_id = d.band_id
    and b.state = 'A'
    and b.Eff_Date < sysdate and
    b.exp_date > sysdate
    and b.begin_date < sysdate
    and b.end_date > sysdate
    and '#10030#10044#200109#218265#' like '%#' || a.group_id || '#%'
    and to_number(a.Right_Limit) <= 0
    --and (a.Chn_Class_Limit like '%#' ||  || '#%' or
        --trim(:channel_segment) is null)
    and 0 = Offer_Login_Limit_Check(b.offer_id,'nf0S01')

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.04       0.05          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch      149      5.01       5.70          0       2920          0        2206
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      151      5.05       5.75          0       2920          0        2206

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 77  

Rows     Row Source Operation
-------  ---------------------------------------------------
   2206  HASH JOIN  (cr=138064 pr=0 pw=0 time=21087739 us)
     56   TABLE ACCESS FULL BAND (cr=7 pr=0 pw=0 time=226 us)
   2243   HASH JOIN  (cr=138057 pr=0 pw=0 time=21180773 us)
   2243    MERGE JOIN  (cr=137764 pr=0 pw=0 time=5030939 us)
  16318     TABLE ACCESS BY INDEX ROWID PRODUCT_OFFER (cr=136792 pr=0 pw=0 time=16775468 us)
  22524      INDEX FULL SCAN PRODUCT_OFFER_IDX (cr=135218 pr=0 pw=0 time=19303965 us)(object id 176928)
   2243     SORT JOIN (cr=972 pr=0 pw=0 time=1322567 us)
   5294      TABLE ACCESS BY INDEX ROWID REGION (cr=972 pr=0 pw=0 time=1166350 us)
  82473       INDEX RANGE SCAN IDX_REGION_FUN (cr=151 pr=0 pw=0 time=164992 us)(object id 241945)
  20696    INDEX FAST FULL SCAN IDX_REGION_COM_1 (cr=293 pr=0 pw=0 time=41547 us)(object id 241946)


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



The execution plan of this function( OFFER_LOGIN_LIMIT_CHECK):
SQL>  select OFFER_LOGIN_LIMIT_CHECK(20097,'nf0S01') from dual;


Execution Plan
----------------------------------------------------------
Plan hash value: 1546270724

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------


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




The sql trace of function( OFFER_LOGIN_LIMIT_CHECK) :
SELECT MAX (CNUM) 
FROM
 (SELECT COUNT (0) CNUM FROM SBANDOFFER WHERE ELEMENT_CODE = :B2 AND 
  ELEMENT_TYPE = 'gh' AND OFFER_ID = :B1 AND BAND_TYPE = 80 AND STATE = '1' 
  AND EFFDATE <= SYSDATE AND EXPDATE >= SYSDATE UNION SELECT COUNT (0) CNUM 
  FROM DLOGINROLEREL A, SBANDOFFER B WHERE A.LOGIN_NO = :B2 AND A.POWER_CODE =
   B.ELEMENT_CODE AND ELEMENT_TYPE = 'js' AND BAND_TYPE = 80 AND OFFER_ID = 
  :B1 AND STATE = '1' AND EFFDATE <= SYSDATE AND EXPDATE >= SYSDATE)


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute  22524     13.68      13.00          0          0          0           0
Fetch    22524      2.80       2.50          0     135144          0       22524
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    45048     16.48      15.50          0     135144          0       22524

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 77     (recursive depth: 1)



Here are some tables and their records:
region                            has 91,007 records
product_offer                 has  22,523 records
pricing_plan                    has 20,695 records
brand                             has 56 records
sbandoffer                      has 2 records
dloginrolerel(synonyms)  has 28,417 records


I have already added the indexes for the outer sql to reduce the cost from 374 to 150.
But the the consistent gets seems not reduce that much.
I notice that the function will cost 6 consistents gets per execution. It seems it not very high.
But if this function goes with the sql, it will cost a very high consistent gets, if I remove this function, the sql only cost 1903 consistents gets.


So what I am thinking there should be two ways to reduce the consistent gets:
The first one is reduce the recursive call of the sql.
The second is reduce the consistent gets of the function. (but it seems that the consistent gets in this function is very low, only 6.)


Any ideas or suggestions, thanks very much.

BR,
Milo


Re: How to reduce the consistent gets of this sql [message #513377 is a reply to message #513370] Mon, 27 June 2011 02:57 Go to previous messageGo to next message
hkchital
Messages: 128
Registered: September 2008
Location: Singapore
Senior Member
PRODUCT_OFFER returns 22,524 rows causing the function to be executed 22,524 times.
That is why the consistent gets for a single execution of the SQL query is high

You need to merge the function's sql code into the query itself.


Hemant K Chitale
Re: How to reduce the consistent gets of this sql [message #513381 is a reply to message #513377] Mon, 27 June 2011 03:15 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Hi, Hemant
Thanks for reply.
Is there any other ways to reduce the consistent gets ? Because this function will called by many applications, and many applications has used this sql.
so maybe it can not be removed or replace in this sql directly in current scenario.

BR,
Milo
Re: How to reduce the consistent gets of this sql [message #513384 is a reply to message #513381] Mon, 27 June 2011 03:47 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Since pretty much all your consistent gets are coming from the function call what other way do you think there may be?
You can't noticebly reduce the gets of the main query or the query in the function. So that leaves the number of times the function is called.
Hemant's suggestion is the only viable one.
Re: How to reduce the consistent gets of this sql [message #513386 is a reply to message #513384] Mon, 27 June 2011 04:28 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Oh, ok.
But can we reduce the consistent gets inside the function?

Thanks very much.
Milo
Re: How to reduce the consistent gets of this sql [message #513387 is a reply to message #513386] Mon, 27 June 2011 04:34 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
You want to reduce the consistent gets of something that's currently only doing 6?
Re: How to reduce the consistent gets of this sql [message #513388 is a reply to message #513387] Mon, 27 June 2011 04:40 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Yes, If it can be done. Smile
Total consistent gets = Function call times x Function consistent gets , if function call times or function consistent gets can be reduce, then total consistent gets can be reduced, Am I right?
Re: How to reduce the consistent gets of this sql [message #513389 is a reply to message #513388] Mon, 27 June 2011 04:45 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Sure, but removing the function will have a far bigger impact.
Post an explain plan for the function select.
Re: How to reduce the consistent gets of this sql [message #513391 is a reply to message #513389] Mon, 27 June 2011 05:11 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Hi, cookiemonster
Here is the execution plan sql inside the function, please kindly check:
SQL> r
  1  SELECT   MAX (cnum)
  2  FROM   (SELECT   COUNT (0) cnum
  3          FROM   SBANDOFFER
  4          WHERE  ELEMENT_CODE = 'nf0S01'
  5                 AND ELEMENT_TYPE = 'gh'
  6                AND OFFER_ID = '20097'
  7                AND BAND_TYPE = 80
  8                AND STATE = '1'
  9                AND EFFDATE <= SYSDATE
 10                AND EXPDATE >= SYSDATE
 11         UNION
 12         SELECT   COUNT (0) cnum
 13         FROM   dloginrolerel a, sbandoffer b
 14         WHERE  a.login_no = 'nf0S01'
 15                AND a.power_code = b.element_code
 16                AND element_type = 'js'
 17                AND BAND_TYPE = 80
 18                AND OFFER_ID = '20097'
 19                AND STATE = '1'
 20                AND EFFDATE <= SYSDATE
 21*               AND EXPDATE >= SYSDATE)


Execution Plan
----------------------------------------------------------
Plan hash value: 3406188812

------------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |                  |     1 |    13 |     7  (29)| 00:00:01 |
|   1 |  SORT AGGREGATE                   |                  |     1 |    13 |            |          |
|   2 |   VIEW                            |                  |     2 |    26 |     7  (29)| 00:00:01 |
|   3 |    SORT UNIQUE                    |                  |     2 |    84 |     7  (72)| 00:00:01 |
|   4 |     UNION-ALL                     |                  |       |       |            |          |
|   5 |      SORT AGGREGATE               |                  |     1 |    35 |     3  (34)| 00:00:01 |
|*  6 |       TABLE ACCESS BY INDEX ROWID | SBANDOFFER       |     1 |    35 |     2   (0)| 00:00:01 |
|*  7 |        INDEX UNIQUE SCAN          | PK_SBANDOFFER    |     1 |       |     1   (0)| 00:00:01 |
|   8 |      SORT AGGREGATE               |                  |     1 |    49 |     4  (25)| 00:00:01 |
|   9 |       NESTED LOOPS                |                  |     1 |    49 |     3   (0)| 00:00:01 |
|* 10 |        INDEX RANGE SCAN           | DLOGINROLEREL_PK |     1 |    14 |     2   (0)| 00:00:01 |
|* 11 |        TABLE ACCESS BY INDEX ROWID| SBANDOFFER       |     1 |    35 |     1   (0)| 00:00:01 |
|* 12 |         INDEX UNIQUE SCAN         | PK_SBANDOFFER    |     1 |       |     0   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------

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

   6 - filter("STATE"='1' AND "EFFDATE"<=SYSDATE@! AND "EXPDATE">=SYSDATE@!)
   7 - access("ELEMENT_CODE"='nf0S01' AND "ELEMENT_TYPE"='gh' AND "OFFER_ID"=20097 AND
              "BAND_TYPE"=80)
  10 - access("A"."LOGIN_NO"='nf0S01')
  11 - filter("STATE"='1' AND "EFFDATE"<=SYSDATE@! AND "EXPDATE">=SYSDATE@!)
  12 - access("A"."POWER_CODE"="B"."ELEMENT_CODE" AND "ELEMENT_TYPE"='js' AND
              "OFFER_ID"=20097 AND "BAND_TYPE"=80)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          6  consistent gets
          0  physical reads
          0  redo size
        515  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed
Re: How to reduce the consistent gets of this sql [message #513392 is a reply to message #513391] Mon, 27 June 2011 05:14 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Looks about as tuned as it's going to get.
Change the count(0) to count(*)
And make the UNION a UNION ALL.

I don't expect either of those to speed it up though.
Re: How to reduce the consistent gets of this sql [message #513393 is a reply to message #513392] Mon, 27 June 2011 05:34 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Yes, you're right. The cost lower down a little bit after using union all. But the consistent gets still 6.
SQL> r
  1   SELECT   MAX (cnum)
  2  FROM   (SELECT   COUNT (*) cnum
  3          FROM   SBANDOFFER
  4          WHERE  ELEMENT_CODE = 'nf0S01'
  5                 AND ELEMENT_TYPE = 'gh'
  6                AND OFFER_ID = '20097'
  7                AND BAND_TYPE = 80
  8                AND STATE = '1'
  9                AND EFFDATE <= SYSDATE
 10                AND EXPDATE >= SYSDATE
 11         UNION ALL
 12         SELECT   COUNT (*) cnum
 13         FROM   dloginrolerel a, sbandoffer b
 14         WHERE  a.login_no = 'nf0S01'
 15                AND a.power_code = b.element_code
 16                AND element_type = 'js'
 17                AND BAND_TYPE = 80
 18                AND OFFER_ID = '20097'
 19                AND STATE = '1'
 20                AND EFFDATE <= SYSDATE
 21*               AND EXPDATE >= SYSDATE)


Execution Plan
----------------------------------------------------------
Plan hash value: 1146362619

-----------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |                  |     1 |    13 |     5   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE                  |                  |     1 |    13 |            |          |
|   2 |   VIEW                           |                  |     2 |    26 |     5   (0)| 00:00:01 |
|   3 |    UNION-ALL                     |                  |       |       |            |          |
|   4 |     SORT AGGREGATE               |                  |     1 |    35 |            |          |
|*  5 |      TABLE ACCESS BY INDEX ROWID | SBANDOFFER       |     1 |    35 |     2   (0)| 00:00:01 |
|*  6 |       INDEX UNIQUE SCAN          | PK_SBANDOFFER    |     1 |       |     1   (0)| 00:00:01 |
|   7 |     SORT AGGREGATE               |                  |     1 |    49 |            |          |
|   8 |      NESTED LOOPS                |                  |     1 |    49 |     3   (0)| 00:00:01 |
|*  9 |       INDEX RANGE SCAN           | DLOGINROLEREL_PK |     1 |    14 |     2   (0)| 00:00:01 |
|* 10 |       TABLE ACCESS BY INDEX ROWID| SBANDOFFER       |     1 |    35 |     1   (0)| 00:00:01 |
|* 11 |        INDEX UNIQUE SCAN         | PK_SBANDOFFER    |     1 |       |     0   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

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

   5 - filter("STATE"='1' AND "EFFDATE"<=SYSDATE@! AND "EXPDATE">=SYSDATE@!)
   6 - access("ELEMENT_CODE"='nf0S01' AND "ELEMENT_TYPE"='gh' AND "OFFER_ID"=20097 AND
              "BAND_TYPE"=80)
   9 - access("A"."LOGIN_NO"='nf0S01')
  10 - filter("STATE"='1' AND "EFFDATE"<=SYSDATE@! AND "EXPDATE">=SYSDATE@!)
  11 - access("A"."POWER_CODE"="B"."ELEMENT_CODE" AND "ELEMENT_TYPE"='js' AND
              "OFFER_ID"=20097 AND "BAND_TYPE"=80)


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



Anyway, thanks cookiemonster. Smile
Re: How to reduce the consistent gets of this sql [message #513394 is a reply to message #513393] Mon, 27 June 2011 05:37 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
As I suspected you aren't going to be able to reduce the consistent gets of the function.
So if you want to tune the main query you will have to follow Hemant's original suggestion.
Re: How to reduce the consistent gets of this sql [message #513395 is a reply to message #513394] Mon, 27 June 2011 05:42 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Out of curiosity, what columns are on the index PRODUCT_OFFER_IDX?
Re: How to reduce the consistent gets of this sql [message #513398 is a reply to message #513395] Mon, 27 June 2011 05:55 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

offer_id is the column on index product_offer_idx.
Re: How to reduce the consistent gets of this sql [message #513399 is a reply to message #513398] Mon, 27 June 2011 06:02 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Figures. It's full scanning that index. And calling the function for every entry in the index.
An index on :
pricing_plan_id, band_id,state,Eff_Date,exp_date,begin_date,end_date

would probably work better.
Re: How to reduce the consistent gets of this sql [message #513403 is a reply to message #513399] Mon, 27 June 2011 06:27 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

So you means I should create a composite index on pricing_plan_id, band_id, state, eff_date, exp_date, begin_date, end_date OR the normal indexes on every column?
Thanks,
Milo
Re: How to reduce the consistent gets of this sql [message #513408 is a reply to message #513403] Mon, 27 June 2011 06:51 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Composite. Queries very rarely use more than one index per table.
Re: How to reduce the consistent gets of this sql [message #513453 is a reply to message #513381] Mon, 27 June 2011 10:13 Go to previous messageGo to next message
hkchital
Messages: 128
Registered: September 2008
Location: Singapore
Senior Member
> Because this function will called by many applications, and many applications has used this sql.
>so maybe it can not be removed or replace in this sql directly in current scenario.

I am not asking you to drop the function. The function may well make sense for use in multiple other points in the application where it may be used against only a few rows.

It is in *this* query that you shouldn't be using the function but merging it into the query.


Hemant K Chitale

[Updated on: Mon, 27 June 2011 10:14]

Report message to a moderator

Re: How to reduce the consistent gets of this sql [message #513501 is a reply to message #513453] Mon, 27 June 2011 21:44 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

I have create the composite index on pricing_plan_id, band_id,state,Eff_Date,exp_date,begin_date,end_date, but the original sql will not use this index.
So I use hint to see, but the cost goes to very high. "TABLE ACCESS BY INDEX ROWID" after the index full scan raise the cost. And the recursive calls and consistent gets goes to lower.

SQL> r
  1  select /*+ index(b idx_product_offer_com2) */ b.OFFER_ID,
  2          b.OFFER_CODE,
  3          b.OFFER_NAME,
  4          b.OFFER_COMMENTS,
  5          b.BAND_ID,
  6          b.CAN_BE_BUY_ALONE,
  7          b.PRICING_PLAN_ID,
  8          b.PRIORITY,
  9          b.STATE,
 10          to_char(b.EFF_DATE, 'yyyymmdd hh24:mi:ss'),
 11          to_char(b.EXP_DATE, 'yyyymmdd hh24:mi:ss'),
 12          to_char(b.BEGIN_DATE, 'yyyymmdd hh24:mi:ss'),
 13          to_char(b.END_DATE, 'yyyymmdd hh24:mi:ss'),
 14          b.REDOFLAG,
 15          b.MIN_NUM,
 16          b.MAX_NUM,
 17          b.EXP_DATE_OFFSET,
 18          b.EXP_DATE_OFFSET_UNIT,
 19          b.USER_RANGE,
 20          b.OFFER_ATTR_TYPE,
 21          b.OFFER_TYPE,
 22          to_char(b.STATE_CHG_DATE, 'yyyymmdd hh24:mi:ss'),
 23          to_char(b.OFFER_CRT_DATE, 'yyyymmdd hh24:mi:ss'),
 24          b.GROUP_TYPE_ID,
 25          nvl(b.GROUP_LIMIT_RULE, 0),
 26          b.PROD_OFFER_PUBLISHER,
 27          b.CUSTOM_REQUEST,
 28          b.OPERATION_MODLE,
 29          a.GROUP_ID,
 30          a.REGION_NAME,
 31          c.pricing_desc,
 32          d.band_name,
 33          b.eff_type,
 34          b.exp_type,
 35          b.MIN_ORDER_NUM,
 36          b.MAX_ORDER_NUM,
 37          b.IF_CUST_PRICE
 38     from REGION a, PRODUCT_OFFER b, PRICING_PLAN c, BAND d
 39     where a.offer_id = b.Offer_Id
 40      and b.pricing_plan_id = c.pricing_plan_id
 41      and b.band_id = d.band_id
 42      and b.state = 'A'
 43      and b.Eff_Date < sysdate and
 44      b.exp_date > sysdate
 45      and b.begin_date < sysdate
 46      and b.end_date > sysdate
 47      and '#10030#10044#200109#218265#' like '%#' || a.group_id || '#%'
 48      and to_number(a.Right_Limit) <= 0
 49      --and (a.Chn_Class_Limit like '%#' ||  || '#%' or
 50          --trim(:channel_segment) is null)
 51*     and 0 = Offer_Login_Limit_Check_TEST1(b.offer_id,'nf0S01')

2206 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3806189357

---------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                        |   134 | 36314 |  5981   (1)| 00:01:12 |
|*  1 |  HASH JOIN                     |                        |   134 | 36314 |  5981   (1)| 00:01:12 |
|*  2 |   TABLE ACCESS BY INDEX ROWID  | REGION                 |   228 |  7752 |    14   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN            | IDX_REGION_FUN         |   819 |       |     3   (0)| 00:00:01 |
|*  4 |   HASH JOIN                    |                        |   134 | 31758 |  5966   (1)| 00:01:12 |
|   5 |    TABLE ACCESS FULL           | BAND                   |    55 |   660 |     3   (0)| 00:00:01 |
|*  6 |    HASH JOIN                   |                        |   134 | 30150 |  5962   (1)| 00:01:12 |
|*  7 |     TABLE ACCESS BY INDEX ROWID| PRODUCT_OFFER          |   156 | 29016 |  5927   (1)| 00:01:12 |
|*  8 |      INDEX FULL SCAN           | IDX_PRODUCT_OFFER_COM2 | 15643 |       |   178   (2)| 00:00:03 |
|   9 |     INDEX FAST FULL SCAN       | IDX_REGION_COM_1       | 18191 |   692K|    34   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

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

   1 - access("A"."OFFER_ID"="B"."OFFER_ID")
   2 - filter('#10030#10044#200109#218265#' LIKE '%#'||"A"."GROUP_ID"||'#%')
   3 - access(TO_NUMBER("RIGHT_LIMIT")<=0)
   4 - access("B"."BAND_ID"="D"."BAND_ID")
   6 - access("B"."PRICING_PLAN_ID"="C"."PRICING_PLAN_ID")
   7 - filter("OFFER_LOGIN_LIMIT_CHECK_TEST1"("B"."OFFER_ID",'nf0S01')=0)
   8 - access("B"."STATE"='A' AND "B"."EXP_DATE">SYSDATE@! AND "B"."END_DATE">SYSDATE@! AND
              "B"."EFF_DATE"<SYSDATE@! AND "B"."BEGIN_DATE"<SYSDATE@!)
       filter("B"."STATE"='A' AND "B"."END_DATE">SYSDATE@! AND "B"."EXP_DATE">SYSDATE@! AND
              "B"."EFF_DATE"<SYSDATE@! AND "B"."BEGIN_DATE"<SYSDATE@!)


Statistics
----------------------------------------------------------
      16410  recursive calls
          0  db block gets
     105928  consistent gets
        174  physical reads
          0  redo size
     264659  bytes sent via SQL*Net to client
       2109  bytes received via SQL*Net from client
        149  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       2206  rows processed



so I try to add offer_id in the composite index, it goes much better, but still it's not best base on the cost value, but the consistent gets and recursive calls lower about 20% compare with the original one.

SQL> r
  1  select /*+ index(b idx_product_offer_com2) */ b.OFFER_ID,
  2          b.OFFER_CODE,
  3          b.OFFER_NAME,
  4          b.OFFER_COMMENTS,
  5          b.BAND_ID,
  6          b.CAN_BE_BUY_ALONE,
  7          b.PRICING_PLAN_ID,
  8          b.PRIORITY,
  9          b.STATE,
 10          to_char(b.EFF_DATE, 'yyyymmdd hh24:mi:ss'),
 11          to_char(b.EXP_DATE, 'yyyymmdd hh24:mi:ss'),
 12          to_char(b.BEGIN_DATE, 'yyyymmdd hh24:mi:ss'),
 13          to_char(b.END_DATE, 'yyyymmdd hh24:mi:ss'),
 14          b.REDOFLAG,
 15          b.MIN_NUM,
 16          b.MAX_NUM,
 17          b.EXP_DATE_OFFSET,
 18          b.EXP_DATE_OFFSET_UNIT,
 19          b.USER_RANGE,
 20          b.OFFER_ATTR_TYPE,
 21          b.OFFER_TYPE,
 22          to_char(b.STATE_CHG_DATE, 'yyyymmdd hh24:mi:ss'),
 23          to_char(b.OFFER_CRT_DATE, 'yyyymmdd hh24:mi:ss'),
 24          b.GROUP_TYPE_ID,
 25          nvl(b.GROUP_LIMIT_RULE, 0),
 26          b.PROD_OFFER_PUBLISHER,
 27          b.CUSTOM_REQUEST,
 28          b.OPERATION_MODLE,
 29          a.GROUP_ID,
 30          a.REGION_NAME,
 31          c.pricing_desc,
 32          d.band_name,
 33          b.eff_type,
 34          b.exp_type,
 35          b.MIN_ORDER_NUM,
 36          b.MAX_ORDER_NUM,
 37          b.IF_CUST_PRICE
 38     from REGION a, PRODUCT_OFFER b, PRICING_PLAN c, BAND d
 39     where a.offer_id = b.Offer_Id
 40      and b.pricing_plan_id = c.pricing_plan_id
 41      and b.band_id = d.band_id
 42      and b.state = 'A'
 43      and b.Eff_Date < sysdate and
 44      b.exp_date > sysdate
 45      and b.begin_date < sysdate
 46      and b.end_date > sysdate
 47      and '#10030#10044#200109#218265#' like '%#' || a.group_id || '#%'
 48      and to_number(a.Right_Limit) <= 0
 49      --and (a.Chn_Class_Limit like '%#' ||  || '#%' or
 50          --trim(:channel_segment) is null)
 51*     and 0 = Offer_Login_Limit_Check_TEST1(b.offer_id,'nf0S01')

2206 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3806189357

---------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                        |   134 | 36314 |   262   (4)| 00:00:04 |
|*  1 |  HASH JOIN                     |                        |   134 | 36314 |   262   (4)| 00:00:04 |
|*  2 |   TABLE ACCESS BY INDEX ROWID  | REGION                 |   228 |  7752 |    14   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN            | IDX_REGION_FUN         |   819 |       |     3   (0)| 00:00:01 |
|*  4 |   HASH JOIN                    |                        |   134 | 31758 |   247   (3)| 00:00:03 |
|   5 |    TABLE ACCESS FULL           | BAND                   |    55 |   660 |     3   (0)| 00:00:01 |
|*  6 |    HASH JOIN                   |                        |   134 | 30150 |   244   (3)| 00:00:03 |
|   7 |     TABLE ACCESS BY INDEX ROWID| PRODUCT_OFFER          |   156 | 29016 |   209   (3)| 00:00:03 |
|*  8 |      INDEX FULL SCAN           | IDX_PRODUCT_OFFER_COM2 |   156 |       |   197   (3)| 00:00:03 |
|   9 |     INDEX FAST FULL SCAN       | IDX_REGION_COM_1       | 18191 |   692K|    34   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

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

   1 - access("A"."OFFER_ID"="B"."OFFER_ID")
   2 - filter('#10030#10044#200109#218265#' LIKE '%#'||"A"."GROUP_ID"||'#%')
   3 - access(TO_NUMBER("RIGHT_LIMIT")<=0)
   4 - access("B"."BAND_ID"="D"."BAND_ID")
   6 - access("B"."PRICING_PLAN_ID"="C"."PRICING_PLAN_ID")
   8 - access("B"."STATE"='A' AND "B"."EXP_DATE">SYSDATE@! AND "B"."END_DATE">SYSDATE@! AND
              "B"."EFF_DATE"<SYSDATE@! AND "B"."BEGIN_DATE"<SYSDATE@!)
       filter("B"."STATE"='A' AND "OFFER_LOGIN_LIMIT_CHECK_TEST1"("B"."OFFER_ID",'nf0S01')=0 AND
              "B"."END_DATE">SYSDATE@! AND "B"."EXP_DATE">SYSDATE@! AND "B"."EFF_DATE"<SYSDATE@! AND
              "B"."BEGIN_DATE"<SYSDATE@!)


Statistics
----------------------------------------------------------
      16338  recursive calls
          0  db block gets
     100895  consistent gets
          0  physical reads
          0  redo size
     264491  bytes sent via SQL*Net to client
       2109  bytes received via SQL*Net from client
        149  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       2206  rows processed


The composite index full scan cost more than the unique index on offer_id.
Could I do something to lower this cost so it will use this execution plan and without using hint?
Thanks very much,
Milo
Re: How to reduce the consistent gets of this sql [message #513502 is a reply to message #513453] Mon, 27 June 2011 22:00 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Hi, Hemant
I am trying to do the equal logic to see if the result goes to more better and see if the developers can accept this solution.
And also another solution is still tried, so that they can choose alternative one.

Thanks very much.
Milo
Re: How to reduce the consistent gets of this sql [message #513509 is a reply to message #513502] Mon, 27 June 2011 22:26 Go to previous messageGo to next message
BlackSwan
Messages: 26766
Registered: January 2009
Location: SoCal
Senior Member
Time spent on SQL that completes in under 5 seconds is wasted effort, IMO.
Re: How to reduce the consistent gets of this sql [message #513527 is a reply to message #513509] Tue, 28 June 2011 01:14 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
@BlackSwan - what makes you think it takes 5 seconds?
@snowball - At this point I'd try rewriting it the way Hemant suggested. Even if you decide not to use that approach it'll give you a benchmark of what is possible.
Re: How to reduce the consistent gets of this sql [message #513548 is a reply to message #513527] Tue, 28 June 2011 02:56 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Yes, I think you're right. It's good to know that.
Thank you so much, cookiemonster and Hemant.
You help me a lot. Smile

Milo
Re: How to reduce the consistent gets of this sql [message #513560 is a reply to message #513548] Tue, 28 June 2011 04:15 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Hi, guys
When I trying to do the equal logic. An error was showed, while it told me 'ORA-00904: "B"."OFFER_ID": invalid identifier', but the b.offer_id is used in main query.
The function definition:
CREATE OR REPLACE FUNCTION OFFER_LOGIN_LIMIT_CHECK
(
  IN_OFFER_ID PRODUCT_OFFER.OFFER_ID%TYPE,
  IS_LOGIN_NO DLOGINMSG.LOGIN_NO%TYPE
) RETURN NUMBER IS
  RETNUM    NUMBER;
  VN_COUNTS NUMBER;
    
BEGIN

  RETNUM    := 0;
  VN_COUNTS  := 0;
 
  IF is_login_no is NULL then
  
    RETURN 0;
    
  END if;

    SELECT   MAX (cnum) INTO VN_COUNTS
      FROM   (SELECT   COUNT (0) cnum
                FROM   SBANDOFFER
               WHERE       ELEMENT_CODE = IS_LOGIN_NO
                       AND ELEMENT_TYPE = 'gh'
                       AND OFFER_ID = IN_OFFER_ID
                       AND BAND_TYPE = 80
                       AND STATE = '1'
                       AND EFFDATE <= SYSDATE
                       AND EXPDATE >= SYSDATE
              UNION
              SELECT   COUNT (0) cnum
                FROM   dloginrolerel a, sbandoffer b
               WHERE       a.login_no = IS_LOGIN_NO
                       AND a.power_code = b.element_code
                       AND element_type = 'js'
                       AND BAND_TYPE = 80
                       AND OFFER_ID = IN_OFFER_ID
                       AND STATE = '1'
                       AND EFFDATE <= SYSDATE
                       AND EXPDATE >= SYSDATE);
                       
      
     IF VN_COUNTS > 0 THEN
        RETNUM := 1;
     END IF;
  
  
  RETURN RETNUM;
  
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN - SQLCODE;
  WHEN OTHERS THEN
    RETURN SQLCODE;
    
END OFFER_LOGIN_LIMIT_CHECK;



I do the equal logic like this:
( 0 =
               (SELECT   MAX (cnum)   
               FROM   (SELECT   COUNT (0) cnum
                       FROM    SBANDOFFER
                       WHERE   ELEMENT_CODE = 'nf0S01'
                               AND ELEMENT_TYPE = 'gh'
                               AND OFFER_ID = b.offer_id
                               AND BAND_TYPE = 80
                               AND STATE = '1'
                               AND EFFDATE <= SYSDATE
                               AND EXPDATE >= SYSDATE
                       UNION ALL
                       SELECT   COUNT (0) cnum
                       FROM    dloginrolerel e, sbandoffer f
                       WHERE   e.login_no = 'nf0S01'
                               AND e.power_code = f.element_code
                               AND element_type = 'js'
                               AND BAND_TYPE = 80
                               AND OFFER_ID = b.offer_id
                               AND STATE = '1'
                               AND EFFDATE <= SYSDATE
                               AND EXPDATE >= SYSDATE ))
                );


Thanks.

Milo

[Updated on: Tue, 28 June 2011 04:24]

Report message to a moderator

Re: How to reduce the consistent gets of this sql [message #513562 is a reply to message #513560] Tue, 28 June 2011 04:29 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

And when I trying to do another sql, it works good.
SQL> select a.id from t4 a where exists (select 'x' from dual where a.id=0);

         ID
---------
          0



It seems that this usage (pass the outer query variable to the inner query) works. But it doesn't work in my equal logic.
Re: How to reduce the consistent gets of this sql [message #513563 is a reply to message #513560] Tue, 28 June 2011 04:31 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
You can only refer to items across nested queries when the queries are one level apart. In this case they are two levels apart.
However I wouldn't do it that way at all. I'd do two seperate not exists sub-queries.
Re: How to reduce the consistent gets of this sql [message #513565 is a reply to message #513563] Tue, 28 June 2011 04:50 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

I have tried with your way like this:
     not exists (    SELECT   'x'
                       FROM    SBANDOFFER
                       WHERE   ELEMENT_CODE = 'nf0S01'
                               AND ELEMENT_TYPE = 'gh'
                               AND OFFER_ID = b.offer_id
                               AND BAND_TYPE = 80
                               AND STATE = '1'
                               AND EFFDATE <= SYSDATE
                               AND EXPDATE >= SYSDATE)  
     and not exists (  SELECT   'x'
                       FROM    dloginrolerel e, sbandoffer f
                       WHERE   e.login_no = 'nf0S01'
                               AND e.power_code = f.element_code
                               AND element_type = 'js'
                               AND BAND_TYPE = 80
                               AND OFFER_ID = b.offer_id
                               AND STATE = '1'
                               AND EFFDATE <= SYSDATE
                               AND EXPDATE >= SYSDATE)


And the return rows is still not correct. Anything I am missing?

Thanks,
BR,
Milo
Re: How to reduce the consistent gets of this sql [message #513568 is a reply to message #513565] Tue, 28 June 2011 05:02 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Not that I can see. You'll need to indentify which rows are being returned that shouldn't and work back from there.
Re: How to reduce the consistent gets of this sql [message #513579 is a reply to message #513568] Tue, 28 June 2011 05:31 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Oh, OK. It will be a tough work.
Thanks.
Re: How to reduce the consistent gets of this sql [message #513705 is a reply to message #513560] Wed, 29 June 2011 01:44 Go to previous messageGo to next message
hkchital
Messages: 128
Registered: September 2008
Location: Singapore
Senior Member
You are obtaining two counts. If either count is non-zero, the Max is non-zero so the comparison to 0 fails.

Therefore, what you need to verify is that *both* counts are 0.

Which could be written as :

SELECT .... main query ...
WHERE ... main query ......
AND
(
0 =
  (SELECT   COUNT (0) cnum
                FROM   SBANDOFFER
               WHERE       ELEMENT_CODE = IS_LOGIN_NO
                       AND ELEMENT_TYPE = 'gh'
                       AND OFFER_ID = IN_OFFER_ID
                       AND BAND_TYPE = 80
                       AND STATE = '1'
                       AND EFFDATE <= SYSDATE
                       AND EXPDATE >= SYSDATE)
AND
0 =
  (SELECT   COUNT (0) cnum
                FROM   dloginrolerel a, sbandoffer b
               WHERE       a.login_no = IS_LOGIN_NO
                       AND a.power_code = b.element_code
                       AND element_type = 'js'
                       AND BAND_TYPE = 80
                       AND OFFER_ID = IN_OFFER_ID
                       AND STATE = '1'
                       AND EFFDATE <= SYSDATE
                       AND EXPDATE >= SYSDATE)
)



Hemant K Chitale

Re: How to reduce the consistent gets of this sql [message #513707 is a reply to message #513705] Wed, 29 June 2011 02:00 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Two not exists subqueries should do the same thing.
Re: How to reduce the consistent gets of this sql [message #513729 is a reply to message #513707] Wed, 29 June 2011 03:28 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Yes, the both ways should do the same thing.

Table t4 has only 0 and -1.
SQL> select * from t4;

        ID
----------
         0
        -1


count way:
SQL> select 'x' from dual
  2  where 1=1 and (0= (select count(0) from t4 where id=1) and 0= (select count(0) from t4 where id=1));

'
-
x

SQL> select 'x' from dual
  2  where 1=1 and (0= (select count(0) from t4 where id=-1) and 0= (select count(0) from t4 where id=1));

no rows selected


not exists way:
SQL> select 'x' from dual
  2  where 1=1 and (not exists (select 'x' from t4 where id=1) and not exists (select 'x' from t4 where id=-1));

no rows selected

SQL> select 'x' from dual
  2  where 1=1 and (not exists (select 'x' from t4 where id=1) and not exists (select 'x' from t4 where id=1));

'
-
x

Finally, I found someone modified some data, so that the return rows change.
And after reexecution, the return rows is the same as the one called by function.

Thanks again, Hemant and cookiemonster. Smile

Milo
Re: How to reduce the consistent gets of this sql [message #513733 is a reply to message #513729] Wed, 29 June 2011 03:34 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
The real question is what difference did it make to the performance?
Re: How to reduce the consistent gets of this sql [message #513739 is a reply to message #513733] Wed, 29 June 2011 03:50 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

You mean the both ways or the return rows changed issue?

Milo

[Updated on: Wed, 29 June 2011 03:52]

Report message to a moderator

Re: How to reduce the consistent gets of this sql [message #513758 is a reply to message #513739] Wed, 29 June 2011 05:19 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
I mean function vs no function
Re: How to reduce the consistent gets of this sql [message #513762 is a reply to message #513758] Wed, 29 June 2011 05:43 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

With the no function the cost goes higher from 150 to 196.
But the consitent gets lower down from 138 thounds to 2 thounds.
And it is faster.
Very cool.

Milo
Re: How to reduce the consistent gets of this sql [message #513764 is a reply to message #513762] Wed, 29 June 2011 05:46 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
The cost was always likely to go higher, Explains don't really factor function calls in, they'll be listed in the predicate section but they are ignored by the stats.
This is an object lesson in why you should be very wary of putting function calls into the where clause of a query.
Re: How to reduce the consistent gets of this sql [message #513825 is a reply to message #513764] Wed, 29 June 2011 10:01 Go to previous messageGo to next message
snowball
Messages: 229
Registered: April 2006
Location: China
Senior Member

Yes, it's true. I learn from this case.
Re: How to reduce the consistent gets of this sql [message #514117 is a reply to message #513825] Fri, 01 July 2011 12:10 Go to previous messageGo to next message
Kevin Meade
Messages: 2103
Registered: December 1999
Location: Connecticut USA
Senior Member
A long post. I flew through some of it so if I am repeating, my appologies.

There are two basic problems from a performance angle with this function.

1) maybe I am reading it wrong, but you seem to be counting the number of rows in each subquery but then you don't actually care how many you counted. This is a very basic mistake that all of us have made over the years. For example, suppose one time you run the count = 100 and a second time it = 1. How does this change the return value? If I read it right, you are only interested in seeing if there is at least one row so in that case, use the ROWNUM=1 construct.

Consider also the idea of splitting up your query inside the function into multiple steps. I don't see the significance of doing both queries if one of them returns a value. The union suggests you care about both but in fact you don't. A value > 0 from either seems to be enough in which case why do the second if the first gives a good result. So if you want to stay with the function, try splitting up the sql into two parts and doing a little more work in PL/SQL to manage the results. Be careful though. Adding more SQL to the function may result in increased recursive calls (see #2 next).

Someone mentioned using existential queries (EXISTS aka. CORRELATED SUBQUERIES). I believe they were working this same angle which is fetch only one row to get the count when you don't really care what the actual count is. The effect is that you will not read all the data when executing your function's queries and that will reduce your consistent gets. I suggest using ROWNUM=1 because you don't have to change too much.

Also, someone suggested creatung indexes specific to the query. If you are creating an index specifically for one query, put all columns referenced in the query (within reason) in the index (this includes columns in the select list if any) so that you can skip table access step. You goal here is two either a) achieve a fast index lookup straight to some row you need and skipping the associated TABLE ACCESS BY ROWID step at the same time, or b) use the index like a table so that you do a fast index scan rather than a full table scan. Both can reduce consistent gets but do so in different ways. Remember that every index you create means more work for Oracle during INSERT/UPDATE/DELETE and table maintenance ops so like most things, you are doing a trade off. Here you are trading off slightly slower performance on data changes for much better performance on specific queries. If you don't get the big bang that you need in your query to justify the tradeoff, rethink the idea of creating the index.

2) a bigger problem with PL/SQL functions called from SQL is that they are very expensive. Your query may show considerable recursive calls (not talking about consistent gets, these are two differnt things). You should see this somewhere (maybe AUTOTRACE?). There is no way to get rid of this aside from dropping the function and inlining its logic inside the main query or getting rid of SQL in the fuction. However, if your issue is recursive calls due to calling PL/SQL from SQL, then inlining the SQL and PL/SQL logic (using native oracle functions) in the main query will be a big benefit performance wise. Someone I believe mentioned this option. You responed with the typical "maintenance burdern". I respond to your reponse with, again it is all about tradeoffs. How badly do you want it to go faster? Try the re-write to see what the benefit is, then decide if you are willing to make the tradeoff to get the benefit. In this case you are trading off redudant code headaches for better performance. I have seen cases where 90% of long running queries was due to this kind of recursive call issue from a seemingly simple PL/SQL function just like this one. The app team I was assisting did not want to re-write it but in the end they had no choice. Their batch stream was hung on it. Try it out, you might have a similar situation.

Good luck, Kevin

vn_counts := null;

begin
   select 1 cnum
   into vn_counts
   from sbandoffer
   where ...
   and rownum = 1
   ;
exception
   when no_data_found then
      null;
end;

if vn_counts is null then
   begin
      select 1 cnum
      into vn_counts
      from dloginrolerel a,sbandoffer b
      where ...
      and rownum = 1
      ;
   exception
      when no_data_found then
         null;
   end;
end if;

if vn_counts is null then vn_counts := 0; end if;
Re: How to reduce the consistent gets of this sql [message #514118 is a reply to message #514117] Fri, 01 July 2011 12:20 Go to previous messageGo to previous message
Kevin Meade
Messages: 2103
Registered: December 1999
Location: Connecticut USA
Senior Member
Here is an example of that recursive call thing I mentioned.

There are four queries here. Notice how the recursive calls change with each of the different queries. In particular notice the last query execution. You cannot it seems get rid of these recursive calls because it is the nature of calling PL/SQL from SQL. Will this be your performance issue? Who knows. But you can find out by re-writing your sql to inline the logic in the main query.

Good luck, Kevin

create or replace function f1 return number as
   v1 number;
begin
   select 1 into v1 from dual;
   return v1;
end;
/
show errors

set autotrace on

select level lvl
from dual
connect by level <= 10
/
select level lvl,f1
from dual
connect by level <= 10
/


SQL> select level lvl
  2  from dual
  3  connect by level <= 10
  4  /

       LVL
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

10 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

-----------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  CONNECT BY WITHOUT FILTERING|      |       |            |          |
|   2 |   FAST DUAL                  |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   1 - filter(LEVEL<=10)


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

SQL> /

       LVL
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

10 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

-----------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  CONNECT BY WITHOUT FILTERING|      |       |            |          |
|   2 |   FAST DUAL                  |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   1 - filter(LEVEL<=10)


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

SQL> select level lvl,f1
  2  from dual
  3  connect by level <= 10
  4  /

       LVL         F1
---------- ----------
         1          1
         2          1
         3          1
         4          1
         5          1
         6          1
         7          1
         8          1
         9          1
        10          1

10 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

-----------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  CONNECT BY WITHOUT FILTERING|      |       |            |          |
|   2 |   FAST DUAL                  |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   1 - filter(LEVEL<=10)


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

SQL> /

       LVL         F1
---------- ----------
         1          1
         2          1
         3          1
         4          1
         5          1
         6          1
         7          1
         8          1
         9          1
        10          1

10 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

-----------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  CONNECT BY WITHOUT FILTERING|      |       |            |          |
|   2 |   FAST DUAL                  |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   1 - filter(LEVEL<=10)


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

SQL> /

       LVL         F1
---------- ----------
         1          1
         2          1
         3          1
         4          1
         5          1
         6          1
         7          1
         8          1
         9          1
        10          1

10 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

-----------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  CONNECT BY WITHOUT FILTERING|      |       |            |          |
|   2 |   FAST DUAL                  |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   1 - filter(LEVEL<=10)


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

SQL>
Previous Topic: enq: TS - contention
Next Topic: PERFORMANCE TUNING
Goto Forum:
  


Current Time: Fri Apr 26 07:55:43 CDT 2024