カレンダテーブルは、時空間のトレードオフを実装します。より多くのスペースを使用することにより、一部の種類のクエリはインデックスを利用できるため、より短い時間で実行されます。CHECK()制約に注意し、dbmsがサポートしていない制約を処理する管理プロセスがある限り、これらは安全です。
粒度が1分である場合、毎年約50万行を生成する必要があります。最小限のカレンダーテーブルは次のようになります。
2011-01-01 00:00:00
2011-01-01 00:01:00
2011-01-01 00:02:00
2011-01-01 00:03:00
2011-01-01 00:04:00
「バケット」分析を行っている場合は、このようなものを使用したほうがよい場合があります。
bucket_start bucket_end
--
2011-01-01 00:00:00 2011-01-01 00:01:00
2011-01-01 00:01:00 2011-01-01 00:02:00
2011-01-01 00:02:00 2011-01-01 00:03:00
2011-01-01 00:03:00 2011-01-01 00:04:00
2011-01-01 00:04:00 2011-01-01 00:05:00
SQLのBETWEEN演算子にはエンドポイントが含まれているため、通常は使用を避ける必要があります。これは、エンドポイントが含まれており、bucket_endを「bucket_startプラス1分からこのサーバーが認識できる最小ビットを引いたもの」と表現するのが難しいためです。(危険は、bucket_endよりマイクロ秒大きい値ですが、bucket_startの次の値よりも小さい値です。)
そのテーブルを作成する場合は、おそらくこのようにします。(私はそれを「カレンダー」と呼ぶべきかどうかについてもっと難しいと思いますが。)
create table calendar (
bucket_start timestamp primary key,
bucket_end timestamp unique,
CHECK (bucket_end = bucket_start + interval '1' minute)
-- You also want a "no gaps" constraint, but I don't think you
-- can do that in a CHECK constraint in PostgreSQL. You might
-- be able to use a trigger that counts the rows, and compares
-- that count to the number of minutes between min(bucket_start)
-- and max(bucket_start). Worst case, you can always run a report
-- that counts the rows and sends you an email.
);
UNIQUE制約は、PostgreSQLに暗黙のインデックスを作成します。
このクエリは、一度に1日分の行(24時間* 60分)を挿入します。
insert into calendar
select coalesce(
(select max(bucket_start) from calendar),
cast('2011-01-01 00:00:00' as timestamp)
)
+ cast((n || 'minute') as interval) as bucket_start,
coalesce(
(select max(bucket_start) from calendar),
cast('2011-01-01 00:00:00' as timestamp)
)
+ cast((n + 1 || ' minute') as interval) as bucket_end
from generate_series(1, (24*60) ) n;
これを関数でラップして、一度に1年を生成できます。おそらく一度に50万行未満をコミットしようとします。
テスト用に2,000万行、さらに2,000万行の「カレンダー」分を生成するのにそれほど時間はかからないはずです。長い昼食。多分太陽の下で午後。