Indici
Crea indici su x.id
e y.id
- che probabilmente hai già se quelle sono le tue chiavi primarie.
Anche un indice a più colonne può aiutare, specialmente con solo indicizza scansioni
a pagina 9.2+:
CREATE INDEX y_mult_idx ON y (id DESC, val)
Tuttavia, nei miei test, questo indice non è stato inizialmente utilizzato. Ho dovuto aggiungere (altrimenti inutile) val
a ORDER BY
per convincere il pianificatore di query che l'ordinamento corrisponde. Vedi query 3 .
L'indice fa poca differenza in questa configurazione sintetica. Ma per le tabelle con più colonne, recuperando val
dal tavolo diventa sempre più costoso, rendendo più appetibile l'indice di "copertura".
Query
1) Semplice
SELECT DISTINCT ON (x.id)
x.id, y.val
FROM x
JOIN y ON y.id <= x.id
ORDER BY x.id, y.id DESC;
Maggiori spiegazioni per la tecnica con DISTINCT
in questa risposta correlata:
Ho eseguito alcuni test perché sospettavo che la prima query non si sarebbe adattata bene. È veloce con un tavolino piccolo, ma non va bene con tavoli più grandi. Postgres non ottimizza il piano e inizia con un cross join (limitato), con un costo di O(N²)
.
2) Veloce
Questa query è ancora piuttosto semplice e si adatta in modo eccellente:
SELECT x.id, y.val
FROM x
JOIN (SELECT *, lead(id, 1, 2147483647) OVER (ORDER BY id) AS next_id FROM y) y
ON x.id >= y.id
AND x.id < y.next_id
ORDER BY 1;
La funzione della finestra lead()
è strumentale. Uso l'opzione per fornire un valore predefinito per coprire il caso d'angolo dell'ultima riga:2147483647
è il numero intero più grande possibile
. Adattati al tuo tipo di dati.
3) Molto semplice e quasi altrettanto veloce
SELECT x.id
,(SELECT val FROM y WHERE id <= x.id ORDER BY id DESC, val LIMIT 1) AS val
FROM x;
Normalmente, sottoquery correlate tendono ad essere lenti. Ma questo può semplicemente scegliere un valore dall'indice (di copertura) ed è altrimenti così semplice da poter competere.
L'ulteriore ORDER BY
voce val
(enfasi in grassetto) sembra inutile. Ma aggiungendolo si convince il pianificatore di query che è possibile utilizzare l'indice a più colonne y_mult_idx
dall'alto, perché l'ordinamento corrisponde. Nota il
nel EXPLAIN
uscita.
Caso di prova
Dopo un vivace dibattito e molteplici aggiornamenti, ho raccolto tutte le domande pubblicate finora e ho creato un banco di prova per una rapida panoramica. Uso solo 1000 righe, quindi SQLfiddle non scade con le query più lente. Ma i primi 4 (Erwin 2, Clodoaldo, a_horse, Erwin 3) scalano linearmente in tutti i miei test locali. Aggiornato ancora una volta per includere la mia ultima aggiunta, migliora il formato e l'ordine in base alle prestazioni ora:
Big SQL Fiddle confrontare le prestazioni.