Можно ли как-то заставить оптимизатор делать Range_scan

feagooor
Дата: 13.10.2015 19:06:53
Имеется табличка:
create table a1(a varchar2(20), b varchar2(20),c varchar2(200));

Имеется индекс на табличке с очень высокой селективностью(практически уникальный):
create index idx_a1 on a1(a,b);

Необходимо выполнить запрос примерно следующего содержания:
select c from a1
where b like '12312%'
and   a in (select * from TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE)))


LIST_TO_TABLE - ф-ия превращения строки в таблицу по разделителю

по данному запросу получается следующий план:
Plan hash value: 1092792744

----------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |               |     1 |   488 |    42   (3)| 00:00:01 |
|*  1 |  HASH JOIN SEMI                    |               |     1 |   488 |    42   (3)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL                | A1            |     1 |   486 |     2   (0)| 00:00:01 |
|   3 |   COLLECTION ITERATOR PICKLER FETCH| LIST_TO_TABLE | 16360 | 32720 |    39   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - access("A"=VALUE(KOKBF$))
   2 - filter("B" LIKE '12312%')
 
Note
-----
   - dynamic sampling used for this statement (level=2)


известно, что в ф-ции LIST_TO_TABLE может находится не более 3 значений. и всё бы хорошо, если бы не LIKE
Возможно ли на приведеном выше запросе получить RANGE SCAN,как если бы он думал что выполняется запрос вроде:
select c from a1
where b like '12312%'
and   a in ('s1','s2','s3')


Plan hash value: 2212992804
 
---------------------------------------------------------------------------------------
| Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |        |     1 |   486 |     1   (0)| 00:00:01 |
|   1 |  INLIST ITERATOR             |        |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| A1     |     1 |   486 |     1   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IDX_A1 |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - access(("A"='s1' OR "A"='s2' OR "A"='s3') AND "B" LIKE '12312%')
       filter("B" LIKE '12312%')
 
Note
-----
   - dynamic sampling used for this statement (level=2)

либо вот так

select c from a1
where b = '12312'
and   a in (select * from TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE)));


Plan hash value: 644285362
 
------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |               |     1 |   488 |    41   (5)| 00:00:01 |
|   1 |  NESTED LOOPS                        |               |       |       |            |          |
|   2 |   NESTED LOOPS                       |               |     1 |   488 |    41   (5)| 00:00:01 |
|   3 |    SORT UNIQUE                       |               | 16360 | 32720 |    39   (0)| 00:00:01 |
|   4 |     COLLECTION ITERATOR PICKLER FETCH| LIST_TO_TABLE | 16360 | 32720 |    39   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN                  | IDX_A1        |     1 |       |     0   (0)| 00:00:01 |
|   6 |   TABLE ACCESS BY INDEX ROWID        | A1            |     1 |   486 |     0   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   5 - access("A"=VALUE(KOKBF$) AND "B"='12312')
 
Note
-----
   - dynamic sampling used for this statement (level=2)


сорри если совсем криво изложил мысль((
orawish
Дата: 13.10.2015 19:20:10
feagooor,

засуньте ваш как-бы-ин в факторинг, с материализацией.
ну и соврите, что кардинальность его ~1
инстр запятнаный
Дата: 13.10.2015 19:40:34
feagooor,

ну, если не справишься с фулсканом, то незачем будет и строку парсить. Может оно быстрее индекса окажется?
orawish
засуньте ваш как-бы-ин в факторинг, с материализацией.
ну и соврите, что кардинальность его ~1
Повторяешься 14637391
orawish
я бы попробовал (в качестве танца с боем бубном по балде ) материализовать коллекцию в темптейбл в факторинге и кардинальностью её пригнуть под плинтус
feagooor
Дата: 13.10.2015 19:42:19
orawish, в смысле как-то вот так?
with t as (select/*+materialize*/ column_value s from TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE)))
SELECT * FROM a1 
where a in (select t.s from t)
and b like '12312%'


всё равно range_scan не получаю
Plan hash value: 1535775476
 
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                             |     1 |  2488 |    45   (3)| 00:00:01 |
|   1 |  TEMP TABLE TRANSFORMATION          |                             |       |       |            |          |
|   2 |   LOAD AS SELECT                    | SYS_TEMP_0FD9D6690_60BBDF6E |       |       |            |          |
|   3 |    COLLECTION ITERATOR PICKLER FETCH| LIST_TO_TABLE               | 16360 | 32720 |    39   (0)| 00:00:01 |
|*  4 |   HASH JOIN SEMI                    |                             |     1 |  2488 |     6  (17)| 00:00:01 |
|*  5 |    TABLE ACCESS FULL                | A1                          |     1 |   486 |     2   (0)| 00:00:01 |
|   6 |    VIEW                             | VW_NSO_1                    | 16360 |    31M|     3   (0)| 00:00:01 |
|   7 |     VIEW                            |                             | 16360 |    31M|     3   (0)| 00:00:01 |
|   8 |      TABLE ACCESS FULL              | SYS_TEMP_0FD9D6690_60BBDF6E | 16360 | 32720 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   4 - access("A"="S")
   5 - filter("B" LIKE '12312%')
 
Note
-----
   - dynamic sampling used for this statement (level=2)
16360
Дата: 13.10.2015 19:46:52
feagooor
всё равно range_scan не получаю
так а кардинальность кто будет уменьшать?
feagooor
Дата: 13.10.2015 19:59:42
воу, работает:) спасибо!
подскажите, а можно как-то сделать тоже самое без вынесения запроса в блок WITH или в отдельную таблицу. чтобы оракл как-то сам это трансформировал в нужную конструкцию
типа
select c from a1
where b like '12312%'
and   a in (select /*+materialize cardinality(1)*/column_value from TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE)))
кит северных морей
Дата: 13.10.2015 20:05:02
SY
Дата: 13.10.2015 20:07:11
SQL> explain plan for
  2  select c from a1
  3  where b like '12312%'
  4  and   a in (select * from TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE)))
  5  /

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------
Plan hash value: 1092792744

----------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |               |     1 |   138 |    39   (3)| 00:00:01 |
|*  1 |  HASH JOIN SEMI                    |               |     1 |   138 |    39   (3)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL                | A1            |     1 |   136 |     9   (0)| 00:00:01 |
|   3 |   COLLECTION ITERATOR PICKLER FETCH| LIST_TO_TABLE |  8168 | 16336 |    29   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------


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

   1 - access("A"=VALUE(KOKBF$))
   2 - filter("B" LIKE '12312%')

Note
-----
   - dynamic sampling used for this statement (level=2)

20 rows selected.

SQL> explain plan for
  2  with t as (
  3             select  column_value
  4               from  TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE))
  5            )
  6  select c from a1
  7  where b like '12312%'
  8  and   a in (select column_value from t)
  9  /

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------
Plan hash value: 1092792744

----------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |               |     1 |   138 |    39   (3)| 00:00:01 |
|*  1 |  HASH JOIN SEMI                    |               |     1 |   138 |    39   (3)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL                | A1            |     1 |   136 |     9   (0)| 00:00:01 |
|   3 |   COLLECTION ITERATOR PICKLER FETCH| LIST_TO_TABLE |  8168 | 16336 |    29   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------


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

   1 - access("A"=VALUE(KOKBF$))
   2 - filter("B" LIKE '12312%')

Note
-----
   - dynamic sampling used for this statement (level=2)

20 rows selected.

SQL> explain plan for
  2  with t as (
  3             select  column_value,
  4                     rownum
  5               from  TABLE(cast(LIST_TO_TABLE('s1,s2,s3,s4',',') as STRING_TBL_TYPE))
  6            )
  7  select c from a1
  8  where b like '12312%'
  9  and   a in (select column_value from t)
 10  /

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------
Plan hash value: 4080658924

---------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |               |     1 |   153 |    32   (4)| 00:00:01 |
|   1 |  NESTED LOOPS                           |               |       |       |            |          |
|   2 |   NESTED LOOPS                          |               |     1 |   153 |    32   (4)| 00:00:01 |
|   3 |    VIEW                                 | VW_NSO_1      |  8168 |   135K|    29   (0)| 00:00:01 |
|   4 |     HASH UNIQUE                         |               |     1 |   135K|            |          |
|   5 |      VIEW                               |               |  8168 |   135K|    29   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------
|   6 |       COUNT                             |               |       |       |            |          |
|   7 |        COLLECTION ITERATOR PICKLER FETCH| LIST_TO_TABLE |  8168 | 16336 |    29   (0)| 00:00:01 |
|*  8 |    INDEX RANGE SCAN                     | IDX_A1        |     1 |       |     1   (0)| 00:00:01 |
|   9 |   TABLE ACCESS BY INDEX ROWID           | A1            |     1 |   136 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

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

   8 - access("A"="COLUMN_VALUE" AND "B" LIKE '12312%')
       filter("B" LIKE '12312%')

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)

26 rows selected.

SQL> 


SY.
orawish
Дата: 14.10.2015 10:02:08
инстр запятнаный
feagooor,

ну, если не справишься с фулсканом, то незачем будет и строку парсить. Может оно быстрее индекса окажется?
orawish
засуньте ваш как-бы-ин в факторинг, с материализацией.
ну и соврите, что кардинальность его ~1
Повторяешься 14637391
orawish
я бы попробовал (в качестве танца с боем бубном по балде ) материализовать коллекцию в темптейбл в факторинге и кардинальностью её пригнуть под плинтус

это да
;)