我正在建立一个分析数据库(我对数据和业务目标有深刻的理解,只有基本到中等的数据库技能)。
我遇到过一些关于构建类似仓库的参考资料,这些仓库实现了“日历表”的概念。这很有意义,而且很容易完成。但是,我看到的大多数示例都是将范围限制为“日”的日历表。我的数据需要分析到小时级别。可能需要几分钟。
我的问题:在空间效率和查询/排序速度方面,小时/分钟级粒度的日历表的实现是否有价值?如果是这样,你能推荐一个表结构和种群方法/例子吗?
我的主要数据表将在任何给定时间包含2千多万行数据,并且用于分析的典型子集在1到5百万范围内。所以,正如你所看到的,那就是很多时间戳字段。
答案 0 :(得分:14)
在PostgreSQL
中,您可以动态生成任意长度和粒度的日历表:
SELECT CAST('2011-01-01' AS DATE) + (n || ' hour')::INTERVAL
FROM generate_series(0, 23) n
这不需要递归(与其他系统一样),是生成volatile结果集的首选方法。
答案 1 :(得分:10)
日历表实现空格/时间权衡。通过使用更多空间,某些类型的查询可以在更短的时间内运行,因为它们可以利用索引。只要你小心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万行“日历”分钟。长午餐。也许是在阳光下的一个下午。
答案 2 :(得分:1)
在我构建的数据仓库中,我使用了单独的CALENDAR和TIME_OF_DAY维度。第一维具有1天的粒度,第二维具有1分钟的粒度。
在另外两个我事先知道的情况下,在小于15分钟的粒度下不需要报告。在这种情况下,为简单起见,我使用的是单个CALENDAR维度,每天有96条记录。
到目前为止,我在Oracle仓库中使用这种方法,但今年夏天我可能会参与PostgreSQL仓库项目。