21

C'è successiva tabella partizionata:Oracle preparato dichiarazione pende

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"); 

Ho domanda di sql, che selezionano 20 record ordinati per data e la transazione:

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 ha generato prossimo piano:

----------------------------------------------------------------------------------------------------------------------------------- 
    | 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') 

Funziona perfettamente.

A proposito, tavolo OUT_SMS è partizionato da TRX_ID campo e OUT_SMS_CREATE_TS_TRX_ID_IX è indice locale(CREATE_TS DESC, TRX_ID DESC) su ogni partizione.

Ma se converto questa query per preparato dichiarazione:

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 genera prossimo piano:

---------------------------------------------------------------------------------------------------------------------------- 
    | 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')) 

Operazione COUNT STOPKEY scompare dal piano. Questa operazione dovrebbe essere dopo che l'indice è stato analizzato per ottenere 20 righe da ciascuna partizione come la prima query.

Come posso scrivere una dichiarazione preparata per avere COUNT STOPKEY nel piano?

+0

Qual è l'istruzione preparata e '?' nel mezzo ? e ?' ? Posso solo darti un consiglio sulle date. Per confrontare le date, rimuovere la porzione del tempo con trunc() a meno che non sia davvero necessario confrontare i secondi. Usa row_number() invece di rownum. – Art

+0

Che tipo di partizionamento è coinvolto qui? La migliore mostra la tabella e l'indice DDL. Inoltre, usa DBMS_Xplan per ottenere il piano di esecuzione e incollarlo nella domanda piuttosto che collegarlo alle immagini per favore. –

+0

"L'intenzione è che la query recuperi solo le righe da una singola partizione?" - No. Devo recuperare i dati da diverse partizioni. –

risposta

1

SQL dinamico è un'opzione? In questo modo è possibile "iniettare" i valori del filtro TRX_ID e CREATE_TS eliminando l'uso delle variabili di binding. Forse il piano generato includerebbe COUNT STOPKEY.

Da SQL dinamico intendevo per te creare l'SQL in modo dinamico e quindi richiamarlo con EXECUTE IMMEDIATE o OPEN. Usando questo puoi usare i tuoi filtri direttamente senza variabili di binding. Esempio:

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'; 

quindi richiamare utilizzando:

EXECUTE IMMEDIATE v_sql; 

o anche:

OPEN cursor_out FOR v_sql; 
+0

Emula le variabili di binding non è interessante per le prestazioni. Scusa, non capisco la tua domanda. –

+0

Vedere la risposta modificata. L'idea è di non usare le variabili di bind. Come stai analizzando il tavolo? –

9

Quando si utilizza variabili di bind, Oracle è costretto ad usare dynamic partition pruning invece di static partition pruning. Il risultato di ciò è che Oracle non sa in tempo di analisi a quali partizioni si accederà, poiché questo cambia in base alle variabili di input.

Ciò significa che quando si utilizzano valori letterali (invece di variabili di bind), sappiamo a quali partizioni sarà possibile accedere dall'indice locale. Pertanto è possibile applicare count stopkey all'output dell'indice prima di eliminare le partizioni.

Quando si utilizzano le variabili di collegamento, lo partition range iterator deve determinare a quali partizioni si sta accedendo. Quindi ha un assegno per assicurarsi che la prima delle tue variabili nelle operazioni tra loro abbia effettivamente un valore più basso della seconda (l'operazione filter nel secondo piano).

Questo può essere facilmente riprodotto, come il seguente caso test mostra:

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 |                                                           
--------------------------------------------------------------------- 

Come nel tuo esempio, la seconda query può filtrare solo le partizioni ad un key in fase di analisi, piuttosto che le partizioni esatte come nel primo esempio.

Questo è uno di quei rari casi in cui i valori letterali possono fornire prestazioni migliori rispetto alle variabili di collegamento. Dovresti investigare se questa è una possibilità per te.

Infine, dici che vuoi 20 righe da ogni partizione. La tua query come stand non lo farà, ti restituirà solo le prime 20 righe in base al tuo ordine. Per 20 righe/partizione, è necessario fare qualcosa di simile:

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

La ragione per cui non stai ricevendo il count stopkey è a che fare con l'operazione filter in linea 4 della " cattivo "piano. Puoi vederlo più chiaramente se ripeti l'esempio sopra, ma senza partizioni.

Questo vi dà i seguenti piani:

----------------------------------------                                                                  
| 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')) 

Come potete vedere, c'è un filter un'operazione in più quando si utilizzano variabili di bind che compaiono prima del sort order by stopkey. Questo succede dopo l'accesso all'indice. Questo sta controllando che i valori delle variabili permetteranno di restituire i dati (la prima variabile nel tuo intervallo ha in realtà un valore inferiore alla seconda). Questo non è necessario quando si usano i letterali perché l'ottimizzatore sa già che 50 è inferiore a 100 (in questo caso). Non sa se: a è inferiore a: b al tempo di analisi comunque.

Perché proprio questo non lo so. Potrebbe essere una progettazione intenzionale di Oracle - non c'è motivo di fare il controllo di stopkey se i valori impostati per le variabili risultano in zero righe - o solo una svista.

+3

La differenza è che nel primo caso il COUNT STOPKEY viene inserito ** all'interno ** della scansione dell'indice dell'intervallo di partizione, il che significa che Oracle è abbastanza intelligente da rendersi conto che per ottenere 20 righe in totale, non serve più di 20 righe per partizione. Questa sottigliezza è persa quando si usano variabili di binding. Non vedo perché l'eliminazione dinamica delle partizioni non possa essere migliorata per spingere il predicato rownum in ogni scansione partizione. Non si fornisce davvero un valido motivo per questo comportamento, né una buona soluzione =) –

+0

@VincentMalgrat - beh, direi che "non utilizzare le variabili di bind" è una soluzione, anche se non necessariamente desiderabile! Se la query viene eseguita raramente e/o c'è un numero limitato di valori usati nel filtro su 'trx_id', l'overhead di analisi addizionale dovrebbe essere minimo, rendendo questo un possibile approccio. –

+0

Concordo con la tua soluzione alternativa, purtroppo l'OP sembra voler utilizzare le variabili di bind. Non sono d'accordo con la tua spiegazione però =) il 'FILTER' non sostituisce' COUNT STOPKEY' dato che sono operazioni fondamentalmente distinte. Mentre spiegate "FILTER" consente a Oracle di ramificare le operazioni impossibili. Il 'COUNT STOPKEY' è un'ottimizzazione che consente a Oracle di recuperare solo 20 righe per partizione poiché ha bisogno di 20 righe in totale. Quando si usano le variabili di bind, questa ottimizzazione è assente, questo è probabilmente un bug (vedere bug relativi al metalink 12873183 e 8500130). –

7

Posso riprodurre i risultati su 11.2.0.3. Ecco il mio banco di prova:

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 | 
---------------------------------------------------------------------------- 

Come nel tuo esempio il ROWNUM predicato è spinto all'interno la partizione gamma di indice di scansione nel primo caso, non nel secondo caso. Quando si utilizzano variabili statiche, il piano mostra che Oracle recupera solo 20 righe per partizione, mentre utilizzando le variabili dinamiche, Oracle preleverà tutte le righe che soddisfano la clausola WHERE in ciascuna partizione. Non sono riuscito a trovare un'impostazione o una configurazione statistica in cui il predicato potrebbe essere spinto quando si utilizzano variabili di collegamento.

ho sperato che si potrebbe usare filtri dinamici con i limiti statici più ampi di ingannare il sistema, ma sembra che il ROWNUM predicato non è utilizzato all'interno di una partizione non appena ci sono variabili dinamiche presenti:

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 | 
---------------------------------------------------------------------------- 

Se questa query è importante e le sue prestazioni sono critiche, è possibile trasformare l'indice in un indice globale. Aumenterà la manutenzione delle partizioni, ma la maggior parte delle operazioni di partizione può essere utilizzata online con le versioni Oracle recenti.In questo caso, un indice globale funzionerà come nella tabella standard non partizionata:

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

Ho la tua idea sull'indice globale, ma il numero delle righe potrebbe essere molto grande e perderò i vantaggi della partizione. –

Problemi correlati