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 nella forecastdate 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)
È stato utile?

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.

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