Domanda

Ho una query SQL che assomiglia a questa:

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

In sostanza, è la parte ORDER BY che rallenta le cose. Se dovessi rimuoverlo, il costo EXPLAIN diminuisce di un ordine di grandezza (oltre 1000x). Ho provato questo:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

Ma questo non dà risultati corretti. C'è un modo semplice per accelerare questo? O dovrò passare un po 'più di tempo con lo strumento EXPLAIN?

È stato utile?

Soluzione

ROW_NUMBER è abbastanza inefficiente in Oracle .

Vedi l'articolo nel mio blog per i dettagli sulle prestazioni:

Per la tua query specifica, ti consiglio di sostituirlo con ROWNUM e assicurarti che venga utilizzato l'indice:

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

Questa query utilizzerà COUNT STOPKEY

Assicurati anche che la colonna non sia nullable, oppure aggiungi la condizione WHERE IS NOT NULL .

Altrimenti l'indice non può essere utilizzato per recuperare tutti i valori.

Nota che non puoi usare ROWNUM TRA: inizio e: fine senza una sottoquery.

ROWNUM è sempre assegnato per ultimo e controllato per ultimo, in questo modo ROWNUM è sempre in ordine senza lacune.

Se si utilizza ROWNUM TRA 10 e 20 , la prima riga che soddisfa tutte le altre condizioni diventerà un candidato per la restituzione, assegnata temporaneamente con ROWNUM = 1 e fallire il test di ROWNUM TRA 10 E 20 .

Quindi la riga successiva sarà candidata, assegnata con ROWNUM = 1 e fallita, ecc., quindi, alla fine, nessuna riga verrà restituita.

Questo dovrebbe essere aggirato inserendo ROWNUM nella sottoquery.

Altri suggerimenti

Mi sembra una query di impaginazione.

Da questo articolo di ASKTOM (circa il 90% in fondo alla pagina):

Devi ordinare per qualcosa unico per queste query di impaginazione, in modo che ROW_NUMBER sia assegnato in modo deterministico alle righe ogni volta.

Anche le tue domande non sono quasi uguali, quindi non sono sicuro di quale sia il vantaggio di confrontare i costi dell'uno con l'altro.

La colonna ORDER BY è indicizzata? Altrimenti è un buon punto di partenza.

Parte del problema è quanto è grande l'intervallo 'inizio' a 'fine' e dove 'vivono'. Supponi di avere un milione di righe nella tabella e desideri che le righe siano comprese tra 567.890 e 567.900, quindi dovrai convivere con il fatto che dovrà passare attraverso l'intera tabella, ordinando praticamente tutto per id, e capire quali righe rientrano in tale intervallo.

In breve, è un sacco di lavoro, motivo per cui l'ottimizzatore gli dà un costo elevato.

Inoltre, non è qualcosa che un indice può aiutare con molto. Un indice darebbe l'ordine, ma nella migliore delle ipotesi ti darà un punto da cui iniziare e poi continuerai a leggere fino a raggiungere la 567.900 voci.

Se stai mostrando all'utente 10 elementi alla volta, potrebbe valere la pena afferrare i primi 100 dal DB, quindi fare in modo che l'app divida i 100 in dieci blocchi.

Trascorri più tempo con lo strumento EXPLAIN PLAN. Se vedi una TABELLA SCANSIONE devi modificare la tua query.

La tua domanda non ha molto senso per me. Interrogare su un ROWID sembra chiedere problemi. Non ci sono informazioni relazionali in quella query. È la vera query con cui stai riscontrando problemi o un esempio che hai inventato per illustrare il tuo problema?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top