0

こんにちは、私は難しい問題に直面しています:

私は天気予報のテーブル (オラクル 9i) を持っています (サイズは何億ものレコードです)。その構成は次のようになります。

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

どこ:

  • stationid予報を作成する可能性のある多くの気象観測所の 1 つを指します。
  • forecastdate予測対象の日付を指します (時刻ではなく日付のみ)。
  • forecastintervalforecastdate予測の時間 (0 ~ 23) を参照します。
  • forecastcreated予測が行われた時間を指し、何日も前になる可能性があります。
  • forecastvalue予測の実際の値を参照します (名前が示すように)。

stationid与えられたものと与えられたものforecastdateとのペアについて、公称数(500など)よりも大きく増加forecastintervalするレコードを決定する必要があります。forecastvalueここに条件の表を示します。

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

上記のシナリオで、3 番目のレコードを取り出したいと思います。これは、予測値が公称 (100 など) だけ増加したレコードです。

テーブルのサイズが非常に大きく (何億ものレコード)、完了するまでに非常に長い時間がかかる (実際、クエリが返されないほど長い) ため、タスクは非常に困難であることが判明しています。

これらの値を取得するためのこれまでの私の試みは次のとおりです。

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)
4

1 に答える 1

1

LAG()を使用するというRexemの提案は正しいアプローチですが、パーティショニング句を使用する必要があります。これは、異なる間隔と異なるステーションの行を追加すると明らかになります...

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> 

誤検知を取り除くために、LAG()をSTATIONID、FORECASTDATE、およびFORECASTINTERVALでグループ化します。以下は、各パーティションウィンドウの最初の計算からNULLを返す内部クエリに依存していることに注意してください。

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> 

大量のデータの操作

テーブルを何億もの行を含むものとして説明します。そのような巨大なテーブルはブラックホールのようなものであり、それらは異なる物理学を持っています。ニーズ、タイムスケール、財務、データベースのバージョンとエディション、およびシステムのデータの他の使用法に応じて、さまざまな潜在的なアプローチがあります。それは5分以上の答えです。

しかし、とにかくここに5分の答えがあります。

テーブルがライブテーブルであると仮定すると、予測が発生したときに予測を追加することでデータが入力されていると考えられます。これは基本的に追加操作です。これは、特定のステーションの予測がテーブル全体に散在していることを意味します。したがって、STATIONIDまたはFORECASTDATEのみのインデックスでは、クラスタリング係数が低くなります。

その仮定で、最初に試してみることをお勧めする1つのことは、にインデックスを作成することです(STATIONID, FORCASTDATE, FORECASTINTERVAL, FORECASTCREATED, FORECASTVALUE)。これにはビルドにある程度の時間(およびディスク容量)がかかりますが、テーブルにまったく触れずにINDEX RANGE SCANでクエリを満たすために必要なすべての列があるため、後続のクエリをかなり高速化する必要があります。

于 2009-10-05T05:42:12.787 に答える