日曆表實現空間/時間折衷。通過使用更多空間,某些種類的查詢可以在更短的時間內運行,因爲它們可以利用索引。只要您謹慎使用CHECK()約束,並且只要您有管理進程來處理您的dbms不支持的任何約束,它們就是安全的。
如果您的粒度爲一分鐘,則每年需要生成約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加上一分鐘,減去此服務器可識別的最小時間」。 (危險值比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中的隱式索引。
此查詢將一次插入一天的行數(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;
您可以將其包裝在一個函數中以一次生成一年。我可能會嘗試一次提交少於50萬行。
不應該花太長時間才能生成2000萬行用於測試,並且還需要2000萬行「日曆」分鐘。午餐很長。也許在陽光下的一個下午。
什麼你說的究竟是「索引的優勢」? – Quassnoi 2011-04-28 20:11:01