21

Там находится рядом секционированной таблицы:Oracle подготовила заявление висит

CREATE TABLE "ERMB_LOG_TEST_BF"."OUT_SMS"(
    "TRX_ID" NUMBER(19,0) NOT NULL ENABLE, 
    "CREATE_TS" TIMESTAMP (3) DEFAULT systimestamp NOT NULL ENABLE, 
    /* other fields... */ 
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
    STORAGE(BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) 
    TABLESPACE "ERMB_LOG_TEST_BF" 
    PARTITION BY RANGE ("TRX_ID") INTERVAL (281474976710656) 
    (PARTITION "SYS_P1358" VALUES LESS THAN (59109745109237760) SEGMENT CREATION IMMEDIATE 
    PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
    NOCOMPRESS LOGGING 
    STORAGE(INITIAL 8388608 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 
    PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 
    BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) 
    TABLESPACE "ERMB_LOG_TEST_BF"); 

CREATE INDEX "ERMB_LOG_TEST_BF"."OUT_SMS_CREATE_TS_TRX_ID_IX" ON "ERMB_LOG_TEST_BF"."OUT_SMS" ("CREATE_TS" DESC, "TRX_ID" DESC) 
    PCTFREE 10 INITRANS 2 MAXTRANS 255 
    STORAGE(
    BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) LOCAL 
    (PARTITION "SYS_P1358" 
    PCTFREE 10 INITRANS 2 MAXTRANS 255 LOGGING 
    STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 
    PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 
    BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) 
    TABLESPACE "ERMB_LOG_TEST_BF"); 

У меня есть SQL запрос, выберите 20 записей отсортированы по дате и сделки:

select rd from (
    select /*+ INDEX(OUT_SMS OUT_SMS_CREATE_TS_TRX_ID_IX) */ rowid rd 
    from OUT_SMS  
    where TRX_ID between 34621422135410688 and 72339069014638591  
     and CREATE_TS between to_timestamp('2013-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') 
         and to_timestamp('2013-03-06 08:57:00', 'yyyy-mm-dd hh24:mi:ss')  
    order by CREATE_TS DESC, TRX_ID DESC 
) where rownum <= 20 

Oracle сгенерировал следующий план:

----------------------------------------------------------------------------------------------------------------------------------- 
    | Id | Operation     | Name      | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | Pstart| Pstop | 
    ----------------------------------------------------------------------------------------------------------------------------------- 
    | 0 | SELECT STATEMENT   |        | 20 | 240 |  | 4788K (1)| 00:05:02 |  |  | 
    |* 1 | COUNT STOPKEY    |        |  |  |  |   |   |  |  | 
    | 2 | VIEW      |        | 312M| 3576M|  | 4788K (1)| 00:05:02 |  |  | 
    |* 3 | SORT ORDER BY STOPKEY |        | 312M|  9G| 12G| 4788K (1)| 00:05:02 |  |  | 
    | 4 |  PARTITION RANGE ITERATOR|        | 312M|  9G|  | 19 (0)| 00:00:01 |  1 | 48 | 
    |* 5 |  COUNT STOPKEY   |        |  |  |  |   |   |  |  | 
    |* 6 |  INDEX RANGE SCAN  | OUT_SMS_CREATE_TS_TRX_ID_IX | 312M|  9G|  | 19 (0)| 00:00:01 |  1 | 48 | 
    ----------------------------------------------------------------------------------------------------------------------------------- 

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

    1 - filter(ROWNUM<=20) 
    3 - filter(ROWNUM<=20) 
    5 - filter(ROWNUM<=20) 
    6 - access(SYS_OP_DESCEND("CREATE_TS")>=HEXTORAW('878EFCF9F6C5FEFAFF') AND 
    SYS_OP_DESCEND("TRX_ID")>=HEXTORAW('36F7E7D7F8A4F0BFA9A3FF') AND 
    SYS_OP_DESCEND("CREATE_TS")<=HEXTORAW('878EFDFEF8FEF8FF') AND 
    SYS_OP_DESCEND("TRX_ID")<=HEXTORAW('36FBD0E9D4E9DBD5F8A6FF')) 
    filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("CREATE_TS"))<=TIMESTAMP' 2013-03-06 08:57:00,000000000' AND 
    SYS_OP_UNDESCEND(SYS_OP_DESCEND("TRX_ID"))<=72339069014638591 AND 
    SYS_OP_UNDESCEND(SYS_OP_DESCEND("TRX_ID"))>=34621422135410688 AND 
    SYS_OP_UNDESCEND(SYS_OP_DESCEND("CREATE_TS"))>=TIMESTAMP' 2013-02-01 00:00:00,000000000') 

Он отлично работает.

Кстати, таблица OUT_SMS является распределял на TRX_ID поле и OUT_SMS_CREATE_TS_TRX_ID_IX является локальным индексом(CREATE_TS DESC, TRX_ID DESC) на каждый раздел.

Но если преобразовать этот запрос подготовленное заявление:

select rd from (
    select /*+ INDEX(OUT_SMS OUT_SMS_CREATE_TS_TRX_ID_IX) */ rowid rd 
    from OUT_SMS  
    where TRX_ID between ? and ?  
     and CREATE_TS between ? and ? 
    order by CREATE_TS DESC, TRX_ID DESC 
) where rownum <= 20 

Oracle генерирует следующий план:

---------------------------------------------------------------------------------------------------------------------------- 
    | Id | Operation     | Name      | Rows | Bytes | Cost (%CPU)| Time  | Pstart| Pstop | 
    ---------------------------------------------------------------------------------------------------------------------------- 
    | 0 | SELECT STATEMENT    |        | 20 | 240 | 14743 (1)| 00:00:01 |  |  | 
    |* 1 | COUNT STOPKEY    |        |  |  |   |   |  |  | 
    | 2 | VIEW      |        | 1964 | 23568 | 14743 (1)| 00:00:01 |  |  | 
    |* 3 | SORT ORDER BY STOPKEY  |        | 1964 | 66776 | 14743 (1)| 00:00:01 |  |  | 
    |* 4 |  FILTER     |        |  |  |   |   |  |  | 
    | 5 |  PARTITION RANGE ITERATOR|        | 1964 | 66776 | 14742 (1)| 00:00:01 | KEY | KEY | 
    |* 6 |  INDEX RANGE SCAN  | OUT_SMS_CREATE_TS_TRX_ID_IX | 1964 | 66776 | 14742 (1)| 00:00:01 | KEY | KEY | 
    ---------------------------------------------------------------------------------------------------------------------------- 

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

    1 - filter(ROWNUM<=20) 
    3 - filter(ROWNUM<=20) 
    4 - filter(TO_TIMESTAMP(:RR,'yyyy-mm-dd hh24:mi:ss')<=TO_TIMESTAMP(:T,'yyyy-mm-dd hh24:mi:ss') AND 
    TO_NUMBER(:ABC)<=TO_NUMBER(:EBC)) 
    6 - access(SYS_OP_DESCEND("CREATE_TS")>=SYS_OP_DESCEND(TO_TIMESTAMP(:T,'yyyy-mm-dd hh24:mi:ss')) AND 
    SYS_OP_DESCEND("TRX_ID")>=SYS_OP_DESCEND(TO_NUMBER(:EBC)) AND 
    SYS_OP_DESCEND("CREATE_TS")<=SYS_OP_DESCEND(TO_TIMESTAMP(:RR,'yyyy-mm-dd hh24:mi:ss')) AND 
    SYS_OP_DESCEND("TRX_ID")<=SYS_OP_DESCEND(TO_NUMBER(:ABC))) 
    filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("TRX_ID"))>=TO_NUMBER(:ABC) AND 
    SYS_OP_UNDESCEND(SYS_OP_DESCEND("TRX_ID"))<=TO_NUMBER(:EBC) AND 
    SYS_OP_UNDESCEND(SYS_OP_DESCEND("CREATE_TS"))>=TO_TIMESTAMP(:RR,'yyyy-mm-dd hh24:mi:ss') AND 
    SYS_OP_UNDESCEND(SYS_OP_DESCEND("CREATE_TS"))<=TO_TIMESTAMP(:T,'yyyy-mm-dd hh24:mi:ss')) 

операции COUNT STOPKEY исчезает из плана. Эта операция должна быть после анализа индекса для получения 20 строк из каждого раздела, как и первый запрос.

Как я могу составить подготовленное заявление, чтобы иметь COUNT STOPKEY в плане?

+0

Что такое подготовленное заявление и '?' между ? а также ?' ? Можете только дать вам один совет о датах. Чтобы сравнить даты, удалите временную часть с помощью trunc(), если вам действительно не нужно сравнивать с секундами. Используйте row_number() вместо rownum. – Art

+0

Какой тип перегородки здесь задействован? Лучше всего показывать таблицу и индекс DDL. Кроме того, используйте DBMS_Xplan, чтобы получить план выполнения и вставить его в вопрос, а не ссылаться на изображения, пожалуйста. –

+0

«Является ли намерение, что запрос только извлекает строки из одного раздела?» - Нет. Мне нужно получить данные из нескольких разделов. –

ответ

1

Является ли Dynamic SQL опцией? Таким образом, вы можете «ввести» значения TRX_ID и CREATE_TS, исключая использование переменных привязки. Возможно, тогда сгенерированный план будет включать COUNT STOPKEY.

С помощью Dynamic SQL я хотел бы, чтобы вы построили SQL динамически, а затем вызвали его с помощью EXECUTE IMMEDIATE или OPEN. Используя это, вы можете напрямую использовать свои фильтры без переменных привязки. Пример:

v_sql VARCHAR2(1000) := 
    'select rd from (
     select /*+ INDEX(OUT_SMS OUT_SMS_CREATE_TS_TRX_ID_IX) */ rowid rd 
     from OUT_SMS  
     where TRX_ID between ' || v_trx_id_min || ' and ' || v_trx_id_maxb || '  
      and CREATE_TS between ' || v_create_ts_min|| ' and ' || v_create_ts_max || ' 
     order by CREATE_TS DESC, TRX_ID DESC 
    ) where rownum <= 20'; 

затем вызвать его с помощью:

EXECUTE IMMEDIATE v_sql; 

или даже:

OPEN cursor_out FOR v_sql; 
+0

Эмуляция переменных привязки не интересна для производительности. Извините, я не понимаю ваш вопрос. –

+0

См. Отредактированный ответ. Идея состоит в том, чтобы не использовать переменные связывания. Как вы анализируете таблицу? –

9

При использовании переменных связывания, Oracle вынуждена использовать dynamic partition pruning вместо static partition pruning. Результатом этого является то, что Oracle не знает во время разбора, к которым будут доступны разделы, поскольку это изменяется на основе ваших входных переменных.

Это означает, что при использовании литеральных значений (вместо переменных привязки) мы знаем, к каким разделам будет обращаться ваш локальный индекс. Поэтому count stopkey может быть применен к выходу индекса, прежде чем обрезать разделы.

При использовании переменных связывания partition range iterator должен определить, к каким разделам вы обращаетесь. Затем он имеет чек, чтобы гарантировать, что первая из ваших переменных в операциях действительно имеет меньшее значение, чем второе (операция filter во втором плане).

Это можно легко воспроизвести, так как следующий тест показывает:

create table tab (
    x date, 
    y integer, 
    filler varchar2(100) 
) partition by range(x) (
    partition p1 values less than (date'2013-01-01'), 
    partition p2 values less than (date'2013-02-01'), 
    partition p3 values less than (date'2013-03-01'), 
    partition p4 values less than (date'2013-04-01'), 
    partition p5 values less than (date'2013-05-01'), 
    partition p6 values less than (date'2013-06-01') 
); 


insert into tab (x, y) 
    select add_months(trunc(sysdate, 'y'), mod(rownum, 5)), rownum, dbms_random.string('x', 50) 
    from dual 
    connect by level <= 1000; 

create index i on tab(x desc, y desc) local; 

exec dbms_stats.gather_table_stats(user, 'tab', cascade => true); 

explain plan for 
SELECT * FROM (
    SELECT rowid FROM tab 
    where x between date'2013-01-01' and date'2013-02-02' 
    and y between 50 and 100 
    order by x desc, y desc 
) 
where rownum <= 5; 

SELECT * FROM table(dbms_xplan.display(null, null, 'BASIC +ROWS +PARTITION')); 

--------------------------------------------------------------------                                                           
| Id | Operation     | Name | Rows | Pstart| Pstop |                                                           
--------------------------------------------------------------------                                                           
| 0 | SELECT STATEMENT   |  |  1 |  |  |                                                           
| 1 | COUNT STOPKEY    |  |  |  |  |                                                           
| 2 | VIEW      |  |  1 |  |  |                                                           
| 3 | SORT ORDER BY STOPKEY |  |  1 |  |  |                                                           
| 4 |  PARTITION RANGE ITERATOR|  |  1 |  2 |  3 |                                                           
| 5 |  COUNT STOPKEY   |  |  |  |  |                                                           
| 6 |  INDEX RANGE SCAN  | I |  1 |  2 |  3 |                                                           
-------------------------------------------------------------------- 

explain plan for 
SELECT * FROM (
    SELECT rowid FROM tab 
    where x between to_date(:st, 'dd/mm/yyyy') and to_date(:en, 'dd/mm/yyyy') 
    and y between :a and :b 
    order by x desc, y desc 
) 
where rownum <= 5; 

SELECT * FROM table(dbms_xplan.display(null, null, 'BASIC +ROWS +PARTITION')); 

---------------------------------------------------------------------                                                           
| Id | Operation     | Name | Rows | Pstart| Pstop |                                                           
---------------------------------------------------------------------                                                           
| 0 | SELECT STATEMENT    |  |  1 |  |  |                                                           
| 1 | COUNT STOPKEY    |  |  |  |  |                                                           
| 2 | VIEW      |  |  1 |  |  |                                                           
| 3 | SORT ORDER BY STOPKEY  |  |  1 |  |  |                                                           
| 4 |  FILTER     |  |  |  |  |                                                           
| 5 |  PARTITION RANGE ITERATOR|  |  1 | KEY | KEY |                                                           
| 6 |  INDEX RANGE SCAN  | I |  1 | KEY | KEY |                                                           
--------------------------------------------------------------------- 

Как и в вашем примере, второй запрос может только фильтровать разделы на key во время синтаксического анализа, а не точные разделов, как в первом примере.

Это один из тех редких случаев, когда литеральные значения могут обеспечить лучшую производительность, чем переменные связывания. Вы должны выяснить, возможно ли это для вас.

Наконец, вы говорите, что хотите получить 20 строк из каждой секции. Ваш запрос как стенд не будет делать этого, он просто вернет вам первые 20 строк в соответствии с вашим заказом. Для 20 строк/раздела, вы должны сделать что-то вроде этого:

select rd from (
    select rowid rd, 
      row_number() over (partition by trx_id order by create_ts desc) rn 
    from OUT_SMS  
    where TRX_ID between ? and ?  
     and CREATE_TS between ? and ? 
    order by CREATE_TS DESC, TRX_ID DESC 
) where rn <= 20 

UPDATE

Причина вы не получаете count stopkey это делать с filter операции в строке 4 раздела " плохой "план. Вы можете увидеть это более четко, если повторить вышеприведенный пример, но без разделения.

Это дает вам следующие планы:

----------------------------------------                                                                  
| Id | Operation    | Name |                                                                  
----------------------------------------                                                                  
| 0 | SELECT STATEMENT  |  |                                                                  
|* 1 | COUNT STOPKEY   |  |                                                                  
| 2 | VIEW     |  |                                                                  
|* 3 | SORT ORDER BY STOPKEY|  |                                                                  
|* 4 |  TABLE ACCESS FULL | TAB |                                                                  
----------------------------------------                                                                  

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

    1 - filter(ROWNUM<=5)                                                                      
    3 - filter(ROWNUM<=5)                                                                      
    4 - filter("X">=TO_DATE(' 2013-01-01 00:00:00', 'syyyy-mm-dd                                                            
       hh24:mi:ss') AND "X"<=TO_DATE(' 2013-02-02 00:00:00', 'syyyy-mm-dd                                                        
       hh24:mi:ss') AND "Y">=50 AND "Y"<=100)                                                                                                                                  

----------------------------------------                                                                  
| Id | Operation    | Name |                                                                  
----------------------------------------                                                                  
| 0 | SELECT STATEMENT  |  |                                                                  
|* 1 | COUNT STOPKEY   |  |                                                                  
| 2 | VIEW     |  |                                                                  
|* 3 | SORT ORDER BY STOPKEY|  |                                                                  
|* 4 |  FILTER    |  |                                                                  
|* 5 |  TABLE ACCESS FULL | TAB |                                                                  
----------------------------------------                                                                  

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

    1 - filter(ROWNUM<=5)                                                                      
    3 - filter(ROWNUM<=5)                                                                      
    4 - filter(TO_NUMBER(:A)<=TO_NUMBER(:B) AND                                                                
       TO_DATE(:ST,'dd/mm/yyyy')<=TO_DATE(:EN,'dd/mm/yyyy'))                                                           
    5 - filter("Y">=TO_NUMBER(:A) AND "Y"<=TO_NUMBER(:B) AND                                                             
       "X">=TO_DATE(:ST,'dd/mm/yyyy') AND "X"<=TO_DATE(:EN,'dd/mm/yyyy')) 

Как вы можете видеть, есть дополнительный filter операция при использовании переменных связывания, возникающие перед sort order by stopkey. Это происходит после доступа к индексу. Это проверяет, что значения для переменных позволят возвращать данные (первая переменная в вашем случае действительно имеет меньшее значение, чем вторая). Это не обязательно при использовании литералов, потому что оптимизатор уже знает, что 50 меньше 100 (в данном случае). Он не знает, будет ли: a меньше: b во время разбора.

Почему именно это я не знаю. Это может быть преднамеренный дизайн Oracle - нет смысла делать проверку стоп-ключа, если значения, установленные для переменных, приводят к нулевым строкам - или просто надзор.

+3

Разница заключается в том, что в первом случае COUNT STOPKEY вставляется ** внутри ** индекса индекса диапазона разделов, что означает, что Oracle достаточно умен, чтобы понять, что для получения 20 рядов всего ему не нужно больше, чем 20 строк на раздел. Эта тонкость теряется при использовании переменных связывания. Я не понимаю, почему динамическая обрезка разделов не может быть усилена, чтобы нажимать предикат rownum при каждом просмотре разделов. Вы действительно не даете веских оснований для этого поведения, ни хорошего обходного пути =) –

+0

@VincentMalgrat - ну, я бы сказал, что «не использовать переменные связывания» - это обходной путь, хотя и не обязательно желаемый! Если запрос выполняется нечасто и/или существует ограниченное количество значений, используемых в фильтре на 'trx_id', тогда дополнительные служебные данные анализа должны быть минимальными, что делает возможным этот подход. –

+0

Я согласен с вашим обходным путем, к сожалению, OP, похоже, хочет использовать переменные связывания. Я не согласен с вашим объяснением, хотя =) 'FILTER' не заменяет' COUNT STOPKEY', поскольку они являются принципиально отличными операциями. Как вы объясните, 'FILTER' позволяет Oracle развернуть невозможные операции. «COUNT STOPKEY» - это оптимизация, которая позволяет Oracle извлекать только 20 строк на раздел, поскольку для этого требуется 20 строк. При использовании переменных привязки эта оптимизация отсутствует, это, скорее всего, ошибка (см. Связанные ошибки metalink 12873183 и 8500130). –

7

Я могу воспроизвести ваши выводы на 11.2.0.3. Вот мой тест:

SQL> -- Table with 100 partitions of 100 rows 
SQL> CREATE TABLE out_sms 
    2 PARTITION BY RANGE (trx_id) 
    3  INTERVAL (100) (PARTITION p0 VALUES LESS THAN (0)) 
    4 AS 
    5 SELECT ROWNUM trx_id, 
    6   trunc(SYSDATE) + MOD(ROWNUM, 50) create_ts 
    7 FROM dual CONNECT BY LEVEL <= 10000; 

Table created 

SQL> CREATE INDEX OUT_SMS_IDX ON out_sms (create_ts desc, trx_id desc) LOCAL; 

Index created 

[static plan] 

SELECT rd 
    FROM (SELECT /*+ INDEX(OUT_SMS OUT_SMS_IDX) */ 
     rowid rd 
      FROM out_sms 
     WHERE create_ts BETWEEN systimestamp AND systimestamp + 10 
      AND trx_id BETWEEN 1 AND 500 
     ORDER BY create_ts DESC, trx_id DESC) 
WHERE rownum <= 20;  
--------------------------------------------------------------------------- 
| Id | Operation     | Name  | Rows | Pstart| Pstop | 
--------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |    |  1 |  |  | 
|* 1 | COUNT STOPKEY    |    |  |  |  | 
| 2 | VIEW      |    |  1 |  |  | 
|* 3 | SORT ORDER BY STOPKEY |    |  1 |  |  | 
| 4 |  PARTITION RANGE ITERATOR|    |  1 |  2 |  7 | 
|* 5 |  COUNT STOPKEY   |    |  |  |  | 
|* 6 |  INDEX RANGE SCAN  | OUT_SMS_IDX |  1 |  2 |  7 | 
--------------------------------------------------------------------------- 

[dynamic]  
---------------------------------------------------------------------------- 
| Id | Operation     | Name  | Rows | Pstart| Pstop | 
---------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    |  1 |  |  | 
|* 1 | COUNT STOPKEY    |    |  |  |  | 
| 2 | VIEW      |    |  1 |  |  | 
|* 3 | SORT ORDER BY STOPKEY  |    |  1 |  |  | 
|* 4 |  FILTER     |    |  |  |  | 
| 5 |  PARTITION RANGE ITERATOR|    |  1 | KEY | KEY | 
|* 6 |  INDEX RANGE SCAN  | OUT_SMS_IDX |  1 | KEY | KEY | 
---------------------------------------------------------------------------- 

Как и в вашем примере ROWNUM предикат выталкивается внутри раздел диапазона индекса сканирования в первом случае, а не во втором случае. При использовании статических переменных план показывает, что Oracle извлекает только 20 строк на раздел, тогда как с использованием динамических переменных Oracle будет извлекать все строки, которые удовлетворяют условию WHERE в каждом разделе. Я не мог найти настройки или конфигурацию статистики, где предикат можно было бы нажать при использовании переменных связывания.

Я надеялся, что вы могли бы использовать динамические фильтры с более широкими статическими пределами для игры системы, но, кажется, что ROWNUM предиката не используются внутри отдельные разделы, как только динамические переменные представляют:

SELECT rd 
    FROM (SELECT /*+ INDEX(OUT_SMS OUT_SMS_IDX) */ 
     rowid rd 
      FROM out_sms 
     WHERE nvl(create_ts+:5, sysdate) BETWEEN :1 AND :2 
      AND nvl(trx_id+:6, 0) BETWEEN :3 AND :4 
      AND trx_id BETWEEN 1 AND 500 
      AND create_ts BETWEEN systimestamp AND systimestamp + 10 
     ORDER BY create_ts DESC, trx_id DESC) 
WHERE rownum <= 20 

Plan hash value: 2740263591 

---------------------------------------------------------------------------- 
| Id | Operation     | Name  | Rows | Pstart| Pstop | 
---------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    |  1 |  |  | 
|* 1 | COUNT STOPKEY    |    |  |  |  | 
| 2 | VIEW      |    |  1 |  |  | 
|* 3 | SORT ORDER BY STOPKEY  |    |  1 |  |  | 
|* 4 |  FILTER     |    |  |  |  | 
| 5 |  PARTITION RANGE ITERATOR|    |  1 |  2 |  7 | 
|* 6 |  INDEX RANGE SCAN  | OUT_SMS_IDX |  1 |  2 |  7 | 
---------------------------------------------------------------------------- 

Если этот запрос важен и его производительность имеет решающее значение, вы можете преобразовать индекс в глобальный индекс. Это увеличит обслуживание разделов, но большинство операций с разделами можно будет использовать в Интернете с последними версиями Oracle.В этом случае глобальный индекс будет работать как со стандартной несегментированной таблицей:

SQL> drop index out_sms_idx; 

Index dropped 

SQL> CREATE INDEX OUT_SMS_IDX ON out_sms (create_ts DESC, trx_id desc); 

Index created 

SELECT rd 
    FROM (SELECT 
     rowid rd 
      FROM out_sms 
     WHERE create_ts BETWEEN :1 AND :2 
      AND trx_id BETWEEN :3 AND :4 
     ORDER BY create_ts DESC, trx_id DESC) 
WHERE rownum <= 20 

------------------------------------------------------------------------ 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| 
------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT |    |  1 | 12 |  2 (0)| 
|* 1 | COUNT STOPKEY  |    |  |  |   | 
| 2 | VIEW    |    |  1 | 12 |  2 (0)| 
|* 3 | FILTER   |    |  |  |   | 
|* 4 |  INDEX RANGE SCAN| OUT_SMS_IDX |  1 | 34 |  2 (0)| 
------------------------------------------------------------------------ 
+0

Я получаю ваше представление о глобальном индексе, но количество строк может быть очень большим, и я потеряю преимущества раздела. –

Смежные вопросы