Oracle: Trova precedente record per una graduatoria delle previsioni
-
19-09-2019 - |
Domanda
Ciao io sono di fronte a un problema difficile:
Ho una tabella (Oracle 9i) delle previsioni meteorologiche (molti 100 di milioni di record in termini di dimensioni.) il cui make-up si presenta così:
stationid forecastdate forecastinterval forecastcreated forecastvalue
---------------------------------------------------------------------------------
varchar (pk) datetime (pk) integer (pk) datetime (pk) integer
dove:
-
stationid
riferisce ad una delle molte stazioni meteorologiche che possono creare una previsione; -
forecastdate
riferisce alla data la previsione è per (solo data non tempo.) -
forecastinterval
riferisce all'ora nellaforecastdate
per la previsione (0 - 23). -
forecastcreated
si riferisce al momento in cui la previsione è stata fatta, può essere molti giorni prima. -
forecastvalue
si riferisce al valore effettivo della previsione (come dice il nome.)
devo determinare per un dato stationid
e una data coppia forecastdate
e forecastinterval
, i record dove un forecastvalue
incrementi più di un numero nominale (dicono 500). Ti faccio vedere una tabella della condizione qui:
stationid forecastdate forecastinterval forecastcreated forecastvalue
---------------------------------------------------------------------------------
'stationa' 13-dec-09 10 10-dec-09 04:50:10 0
'stationa' 13-dec-09 10 10-dec-09 17:06:13 0
'stationa' 13-dec-09 10 12-dec-09 05:20:50 300
'stationa' 13-dec-09 10 13-dec-09 09:20:50 300
Nello scenario precedente, mi piacerebbe tirare fuori il terzo record. Questo è il record in cui il valore di previsione aumentato di un nominale (esempio 100) importo.
Il compito si sta rivelando molto difficile a causa della vastità della tabella (molti 100s di milioni di record.) E prendendo così tanto tempo per finire (così a lungo, infatti, che la mia domanda non è mai tornato.)
Ecco il mio tentativo finora di afferrare questi valori:
select
wtr.stationid,
wtr.forecastcreated,
wtr.forecastvalue,
(wtr.forecastdate + wtr.forecastinterval / 24) fcst_date
from
(select inner.*
rank() over (partition by stationid,
(inner.forecastdate + inner.forecastinterval),
inner.forecastcreated
order by stationid,
(inner.forecastdate + inner.forecastinterval) asc,
inner.forecastcreated asc
) rk
from weathertable inner) wtr
where
wtr.forecastvalue - 100 > (
select lastvalue
from (select y.*,
rank() over (partition by stationid,
(forecastdate + forecastinterval),
forecastcreated
order by stationid,
(forecastdate + forecastinterval) asc,
forecastcreated asc) rk
from weathertable y
) z
where z.stationid = wtr.stationid
and z.forecastdate = wtr.forecastdate
and (z.forecastinterval =
wtr.forecastinterval)
/* here is where i try to get the 'previous' forecast value.*/
and wtr.rk = z.rk + 1)
Soluzione
Il suggerimento di Rexem di utilizzare GAL () è l'approccio giusto, ma abbiamo bisogno di usare una clausola di partizionamento. Questo diventa chiaro una volta aggiungiamo le righe per i diversi intervalli e diverse stazioni di ...
SQL> select * from t
2 /
STATIONID FORECASTDATE INTERVAL FORECASTCREATED FORECASTVALUE
---------- ------------ -------- ------------------- -------------
stationa 13-12-2009 10 10-12-2009 04:50:10 0
stationa 13-12-2009 10 10-12-2009 17:06:13 0
stationa 13-12-2009 10 12-12-2009 05:20:50 300
stationa 13-12-2009 10 13-12-2009 09:20:50 300
stationa 13-12-2009 11 13-12-2009 09:20:50 400
stationb 13-12-2009 11 13-12-2009 09:20:50 500
6 rows selected.
SQL> SELECT v.stationid,
2 v.forecastcreated,
3 v.forecastvalue,
4 (v.forecastdate + v.forecastinterval / 24) fcst_date
5 FROM (SELECT t.stationid,
6 t.forecastdate,
7 t.forecastinterval,
8 t.forecastcreated,
9 t.forecastvalue,
10 t.forecastvalue - LAG(t.forecastvalue, 1)
11 OVER (ORDER BY t.forecastcreated) as difference
12 FROM t) v
13 WHERE v.difference >= 100
14 /
STATIONID FORECASTCREATED FORECASTVALUE FCST_DATE
---------- ------------------- ------------- -------------------
stationa 12-12-2009 05:20:50 300 13-12-2009 10:00:00
stationa 13-12-2009 09:20:50 400 13-12-2009 11:00:00
stationb 13-12-2009 09:20:50 500 13-12-2009 11:00:00
SQL>
Per rimuovere i falsi positivi che gruppo del GAL () per StationID, FORECASTDATE e FORECASTINTERVAL. Si noti che la seguente si basa sulla query interna di ritorno NULL dal primo calcolo di ogni finestra partizione.
SQL> SELECT v.stationid,
2 v.forecastcreated,
3 v.forecastvalue,
4 (v.forecastdate + v.forecastinterval / 24) fcst_date
5 FROM (SELECT t.stationid,
6 t.forecastdate,
7 t.forecastinterval,
8 t.forecastcreated,
9 t.forecastvalue,
10 t.forecastvalue - LAG(t.forecastvalue, 1)
11 OVER (PARTITION BY t.stationid
12 , t.forecastdate
13 , t.forecastinterval
14 ORDER BY t.forecastcreated) as difference
15 FROM t) v
16 WHERE v.difference >= 100
17 /
STATIONID FORECASTCREATED FORECASTVALUE FCST_DATE
---------- ------------------- ------------- -------------------
stationa 12-12-2009 05:20:50 300 13-12-2009 10:00:00
SQL>
Lavorare con grandi volumi di dati
È descrivere le tabelle come contenente molte centinaia di milioni di righe. Tali tabelle enormi sono come buchi neri, hanno un fisico diverso. Ci sono vari approcci possibili, a seconda delle esigenze, tempistiche, le finanze, versione del database e l'edizione, e qualsiasi altro utilizzo dei dati del sistema. E 'più di una risposta di cinque minuti.
Ma ecco la risposta cinque minuti in ogni caso.
Assumendo che il tavolo è la tabella dal vivo è presumibilmente essendo popolando con l'aggiunta di previsioni in cui si verificano, che è fondamentalmente un'operazione accodamento. Ciò significherebbe previsioni per un dato stazione sono sparsi in tutto il tavolo. Di conseguenza, gli indici di appena StationID o addirittura FORECASTDATE avrebbero un povero fattore di clustering.
In tale ipotesi, l'unica cosa che vorrei suggerire di provare prima è la costruzione di un indice su (STATIONID, FORCASTDATE, FORECASTINTERVAL, FORECASTCREATED, FORECASTVALUE)
. Questo richiederà un certo tempo (e spazio su disco) per costruire, ma dovrebbe velocizzare le query successive in modo considerevole, perché ha tutte le colonne necessarie per soddisfare la domanda con un indice di scansione RANGE senza toccare il tavolo a tutti.