2009-12-01 48 views
6

La tabella ha la chiave primaria surrogata generata dalla sequenza. Sfortunatamente, questa sequenza è usata per generare le chiavi per alcune altre tabelle (non l'ho progettata e non posso cambiarla).Selezionare `n` ultimi record inseriti nella tabella - oracle

Qual è il modo più veloce per selezionare gli ultimi record inseriti in Oracle n in ordine decrescente (ultimo inserito in alto)?

n è un numero relativamente piccolo - il numero di record da visualizzare nella pagina - probabilmente non più grande di 50.

tavolo ha ora 30.000.000 record con 10-15 migliaia di nuovi record al giorno.

Il database è Oracle 10g.

Edit:
In risposta a un commento: La domanda è stata motivata con il piano di esecuzione per la query:

select * from MyTable order by primarykeyfield desc 

Piano di esecuzione era:

--------------------------------------------- 
| Id | Operation   | Name  |  
--------------------------------------------- 
| 0 | SELECT STATEMENT |    | 
| 1 | SORT ORDER BY  |    | 
| 2 | TABLE ACCESS FULL| MyTable  | 
--------------------------------------------- 

Mi ha sorpreso che Oracle vuole per eseguire la scansione completa della tabella e l'ordinamento quando ha indice sul campo di ordinamento.

La query di risposta accettata utilizza l'indice ed evita l'ordinamento.

Modifica 2:
Re. Il commento di APC: l'ordinamento è stato una parte che mi ha sorpreso. Mi aspettavo che Oracle usasse l'indice per recuperare le righe nell'ordine previsto. piano di esecuzione per la query:

select * from (select * from arh_promjene order by promjena_id desc) x 
    where rownum < 50000000 

utilizza l'indice invece di accesso completo tavolo e ordinare (condizione di preavviso rownum < 50.000.000 - questo è il modo più di numero di record nella tabella e Oracle sa che deve recuperare tutti i record dalla tabella). Questa query restituisce tutte le righe come la prima interrogazione, ma con le seguenti piano di esecuzione:

| Id | Operation      | Name   | 
------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    | 
|* 1 | COUNT STOPKEY    |    | 
| 2 | VIEW      |    | 
| 3 | TABLE ACCESS BY INDEX ROWID| MyTable  | 
| 4 |  INDEX FULL SCAN DESCENDING| SYS_C008809 | 

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

    1 - filter(ROWNUM<50000000)       

era insolito per me che Oracle sta creando diversi piani di esecuzione di queste due query che restituiscono essenzialmente lo stesso set di risultati.

Edit 3: il commento di Re Amoq:

Oracle non sa che 50M è maggiore del numero di righe. Certo, ha statistiche, ma potrebbero essere vecchie e sbagliate - e Oracle non avrebbe mai consentire a se stesso di fornire un risultato errato solo perché le statistiche sono sbagliato.

Sei sicuro? Nelle versioni Oracle fino a 9 si consigliava di aggiornare manualmente le statistiche di volta in volta. Dalla versione 10 Oracle aggiorna automaticamente le statistiche. A che cosa servono i dati statistici se Oracle non li usa per l'ottimizzazione delle query?

+0

Perché è spiacevole che la sequenza venga utilizzata anche per altre tabelle? Non importa per la query recuperare gli ultimi n record inseriti perché una sequenza non è mai garantita essere priva di barriere da parte di Oracle. Quindi non è possibile fare un semplice id tra max-n e max in ogni caso. – tuinstoel

+0

La tua query seleziona * tutte * le colonne per * tutte * le righe. Perché sei sorpreso che Oracle esegua una scansione completa? In quale altro modo otterrebbe i dati per soddisfare questa query? – APC

+0

Oracle non * sa * che 50M è maggiore del numero di righe. Certo, ha delle statistiche, ma potrebbero essere vecchie e sbagliate - e Oracle * non * si permetterebbe mai di fornire un risultato errato solo perché le statistiche sono sbagliate. –

risposta

15

Uso ROWNUM:

select 
    * 
from 
    (
    select 
     * 
    from 
     foo 
    order by 
     bork 
    ) x 
where 
    ROWNUM <= n 

noti che rownum viene applicato prima ordinamento per una sottoquery, è per questo che avete bisogno di due query nidificate, altrimenti devi semplicemente ottenere n righe casuali.

+0

esattamente ........ –

+0

Ciò implica che il bork è ordinabile ... È compatibile con l'OP? Potrebbe essere benissimo, ma se così fosse sarebbe strano che l'OP ponga una domanda così semplice. –

+1

Se prendiamo il bork come chiave primaria generata dalla sequenza che l'OP ha menzionato, e supponendo che sia monotonicamente crescente, allora questa query funzionerà. – Dan

4

Sarà visualizzato molte più volte di quanto sia stato aggiornato? Che ne dici di mantenere un'altra tabella degli ID delle ultime N righe inserite (usa un trigger per eliminare l'ID più piccolo da questa tabella e aggiungi una nuova riga con l'attuale inserito).

Ora si dispone di una tabella che registra gli ID delle ultime N righe inserite. Ogni volta che vuoi la N, basta unirla al tavolo principale. Se N cambia, scegli il massimo che può essere, quindi filtra dopo ... naturalmente potresti non trovarlo così veloce per la tua app (la manutenzione di questa tabella potrebbe annullare qualsiasi guadagno in termini di prestazioni)

3

Questo può aiutarti se non si conosce il nome dei campi o qualcosa di diverso nome della tabella ....

select * from (
    select * from(
    select rownum r,student.* from student where rownum<=(
     select max(rownum) from student 
    ) 
) order by r desc 
) where r<=10; 
3

Prova a fare un suggerimento index_desc

select /*+ index_desc(MyTable,<PK_index>) */ * from MyTable order by primarykeyfield desc 
3

Nei casi in cui non si dispone di un strettamente crescente, è possibile utilizzare anche ORA_ROWSCN (numero di modifica del sistema) come approssimazione di S.

select * from (select * from student order by ORA_ROWSCN desc) where rownum<10 

Attenzione: questo non è esatto, poiché le annotazioni Oracle sola SCN per blocco, non per riga. Sembra anche fare una scansione completa della tabella - probabilmente oracle non è abbastanza intelligente per ottimizzare questo tipo di ordinamento. Quindi questa potrebbe non essere una buona idea per l'uso di produzione.

Problemi correlati