Re: Inefficient query plan using large in-list

From: S M <xt.and.r_at_gmail.com>
Date: Thu, 16 May 2019 20:57:09 +0300
Message-ID: <CAOVevU5gMQ+gzw2Dx31DCo3VTjrruN7WvOF50cv_UDAkTRyA+A_at_mail.gmail.com>



Andy,
I've just checked the solution with "materialize" on 18.5 and I see it requires a bit more "materialize" steps: Please see my comment here:
https://gist.github.com/xtender/24d29af63a398200d4d87ebc4a4a27b8

"Materialize" solution for Oracle 18.5:
```sql
with z(a) as (select/*+ materialize */ * from table(sys.odcinumberlist(1)))

    ,v(a) as (select/*+ materialize */ * from z where 1=1) select/*+ leading(v t) use_nl(t) index(t) */ t.* from vtest t
where exists(select * from v where t.a=v.a) ```
Plan:
```sql
Plan hash value: 434338359



| Id | Operation | Name

   | Rows | Bytes | Cost (%CPU)| Time |



| 0 | SELECT STATEMENT |
  |     1 |    20 |    58   (4)| 00:00:01 |

| 1 | TEMP TABLE TRANSFORMATION |
| | | | |
| 2 | LOAD AS SELECT (CURSOR DURATION MEMORY)|
SYS_TEMP_0FD9D67BE_327432A | | | | |

| 3 | COLLECTION ITERATOR CONSTRUCTOR FETCH |
  | 8168 | 16336 | 29 (0)| 00:00:01 |
| 4 | HASH GROUP BY |
  |     1 |    20 |    29   (7)| 00:00:01 |

| 5 | NESTED LOOPS |
| 1000 | 20000 | 28 (4)| 00:00:01 |
| 6 | NESTED LOOPS |
| 1000 | 20000 | 28 (4)| 00:00:01 |
| 7 | VIEW |
| 8168 | 103K| 3 (0)| 00:00:01 |
| 8 | HASH UNIQUE |
| 1 | 16336 | | |
| 9 | TABLE ACCESS FULL |
SYS_TEMP_0FD9D67BE_327432A | 8168 | 16336 | 3 (0)| 00:00:01 | |* 10 | INDEX RANGE SCAN | ITEST | 1000 | | 2 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID | XTEST
  | 1000 | 7000 | 24 (0)| 00:00:01 |

Predicate Information (identified by operation id):


  10 - access("A"="V"."A")
```
Unfortunately we need to wrap table() function twice on 18.5. I haven't tried it on 19.3 yet, will do later.

On Thu, May 16, 2019 at 8:50 PM S M <xt.and.r_at_gmail.com> wrote:

> Senthil,
>
> But in your case I don't see the reason to use collections. You showed
>>> this code:
>>> select sh.*
>>> from   table(cast(multiset(select level from dual
>>>                            connect by level <= length
>>> (regexp_replace(:in_list, '[^,]+')) + 1) as sys.OdciNumberList)) xt,
>>>        secmaster_history sh
>>> where  sh.security_alias = xt.column_value
>>> and    to_date('15-MAY-2010') between effective_date and
>>> nvl(expiration_date,sysdate) ;
>>>
>>> and looks like there should be regexp_substr(...) instead of level:
>>> select sh.*
>>> from   table(cast(multiset(select *regexp_substr(:in_list,
>>> '[^,]+',1,level)* from dual
>>>                            connect by level <= length
>>> (regexp_replace(:in_list, '[^,]+')) + 1) as sys.OdciNumberList)) xt,
>>>        secmaster_history sh
>>> where  sh.security_alias = xt.column_value
>>> and    to_date('15-MAY-2010') between effective_date and
>>> nvl(expiration_date,sysdate) ;
>>>
>>> In this case you don't need table(cast multiset(...)), just use inline
>>> view:
>>> select sh.*
>>> from   (select regexp_substr(:in_list, '[^,]+',1,level) as val
>>>         from dual
>>>         connect by level <= length (regexp_replace(:in_list, '[^,]+')) +
>>> 1) xt,
>>>        secmaster_history sh
>>> where  sh.security_alias = xt.val
>>> and    to_date('15-MAY-2010') between effective_date and
>>> nvl(expiration_date,sysdate) ;
>>>
>>
> Have you checked this part?
> Why do you need table() function here?
>
> --
> Best regards,
> Sayan Malakshinov
> Oracle performance tuning engineer
> Oracle ACE Associate
> http://orasql.org
>


-- 
Best regards,
Sayan Malakshinov
Oracle performance tuning engineer
Oracle ACE Associate
http://orasql.org

--
http://www.freelists.org/webpage/oracle-l
Received on Thu May 16 2019 - 19:57:09 CEST

Original text of this message