Question

Salut, je suis face à un problème difficile:

J'ai une table (oracle 9i) des prévisions météorologiques (nombre de 100 millions de disques dans la taille.) dont la composition ressemble à ceci:

stationid    forecastdate    forecastinterval    forecastcreated    forecastvalue
---------------------------------------------------------------------------------
varchar (pk) datetime (pk)   integer (pk)        datetime (pk)      integer

où:

  • stationid se réfère à l'une des nombreuses stations météorologiques qui peuvent créer une prévision;
  • forecastdate se réfère à la date de la prévision (date seulement pas le temps.)
  • forecastinterval se réfère à l'heure dans l' forecastdate pour la prévision (0 - 23).
  • forecastcreated se réfère à la fois la prévision a été faite, peut-être plusieurs jours à l'avance.
  • forecastvalue se réfère à la valeur réelle de la prévision (comme son nom l'indique.)

J'ai besoin de déterminer, pour un stationid et un forecastdate et forecastinterval paire, les dossiers où un forecastvalue incréments plus qu'un nombre nominal (500).Je vais vous montrer un tableau de la condition ici:

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

Dans le scénario ci-dessus, j'aimerais sortir le troisième album.C'est l'enregistrement où la prévision de la valeur a augmenté d'un nominal (disons 100) montant.

La tâche s'avère très difficile en raison de la taille du tableau (nombre de 100s de millions d'enregistrements). et de prendre autant de temps pour finir (si longtemps en fait que ma requête n'a jamais retourné.)

Voici ma tentative de mesure de saisir ces valeurs:

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)
Était-ce utile?

La solution

Rexem la suggestion de l'utilisation de LAG() est la bonne approche, mais nous avons besoin d'utiliser un partitionnement de la clause.Cela devient évident une fois que nous avons ajouter des lignes pour les différents intervalles de temps et les différentes stations de...

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> 

Pour supprimer les faux positifs que nous groupe le GAL() par STATIONID, FORECASTDATE et FORECASTINTERVAL.Notez que celui-ci s'appuie sur l'intérieure de la requête qui renvoie la valeur NULL à partir de la première de calcul de chaque fenêtre partition.

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> 

Travailler avec de grands volumes de données

Vous décrivez vos tables contenant plusieurs centaines de millions de lignes.De tels tableaux sont comme des trous noirs, ils ont une autre physique.Il existe plusieurs approches possibles, en fonction de vos besoins, les délais, les finances, la base de données de la version et de l'édition, et toute autre utilisation de vos données du système d'information.C'est plus que cinq minutes à répondre.

Mais voici les cinq minutes à répondre de toute façon.

En supposant que votre table est la table en direct c'est sans doute en cours de remplissage par l'ajout prévisions à mesure qu'ils surviennent, qui est essentiellement une opération de concaténation.Cela signifierait prévisions pour chaque station sont dispersés dans tout le tableau.Par conséquent, les indices sur STATIONID ou même FORECASTDATE aurait un mauvais facteur groupement.

Dans cette hypothèse, la seule chose que je vous suggère d'essayer le premier est la création d'un index sur (STATIONID, FORCASTDATE, FORECASTINTERVAL, FORECASTCREATED, FORECASTVALUE).Cela va prendre un peu de temps (et de l'espace disque) pour construire, mais il devrait accélérer les requêtes ultérieures considérablement, car il a toutes les colonnes nécessaires pour satisfaire à la requête avec un INDEX RANGE SCAN sans toucher la table.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top