1

我正在创建一个表来存储每周的产品数据,实际上是计数器。

例子:

 id = 1
 productId = 195
 DateTime = 01/07/2012
 Counter = 0

我的问题是关于数据库存储空间、查询灵活性和性能。

而不是 DateTime 列,我考虑使用 SmallInt 'WeekNumber' 列。

我将决定星期的开始日期(基准日期)。假设 2012 年 10 月 10 日。

对于每个产品和每周,都会有一行代表我每天计算的总内容(即特定产品页面的浏览量)。

从我读过的内容:

日期列是 4 个字节

SmallInt 是 2 个字节

我想尽可能多地节省空间,但我希望能够根据日期范围(2012 年 8 月至 2013 年 9 月)、特定年份的特定星期等查询数据库。

这种架构方法是否良好,或者我会发现自己在 SQL 性能、查询灵活性、索引等方面存在问题。

4

2 回答 2

3

考虑一下您将要做出的牺牲和复杂性,以节省2 个字节 一个字节....

为了使用,smallint您将通过一个函数传递对数据的每次调用,以从您自己的任意日期开始获取其“周数”......这既不是更高效也不是更清晰。

同样,查询也不那么灵活,因为每个查询都需要根据您的神奇“开始日期”进行比较,而不仅仅是日期比较/组。您的查询可能不是 SARGable 并且可能会更慢

编辑:根据您的评论,您有 50GB 的硬限制....对于您正在讨论的聚合数据库来说,这是一个很大的空间。通过使这复杂化,您正在招致过度的压力和可持续性的丧失。

根据 MySQL,DATE类型只有 3 个字节,而 2 个字节SMALLINT

http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html

因此,您将每行保存一个字节(您说每周 2000 字节)......所以我们说每周 2KB,每年 104 KB......

于 2012-07-30T15:49:51.103 回答
2

如果此表没有子表(没有引用它的外键),为了节省空间,您可以考虑省略代理主键(id),而是使用复合键(productId,date_)作为主键。(根据您的描述,听起来您希望将这些列的组合设为 UNIQUE,并且将这两个列都设为 NOT NULL。

如果您要存储的是“周”标识符而不是 DATE,那么在数据库方面没有问题,只要您的查询没有将该列包装在表达式中以获取要在谓词中使用的 DATE 值. 也就是说,为了性能,您的谓词将需要位于“星​​期标识符”列,例如

WHERE t.product_id = 195 AND t.week_id >= 27 AND t.week_id < 40

像这样在裸列上的谓词将是 sargable(即,允许使用索引。)您不想将该week_id列包装在表达式中以返回 DATE,并在该表达式上使用 WHERE 子句。(在比较的文字方面有表达式不是问题......你只是不希望它们在“表”方面。

这确实将成为您是否可以使用 aweek_id代替 DATE 列的决定因素。

使用“期间 id”代替 DATE 对于整月的期间实施起来相当简单。(“天”也很简单,但在那里实际上没有什么好处。)在“周”期间实施这种方法更加复杂,因为您需要在两年之间进行一周的处理。

例如,考虑一下,今年(2012 年)的最后两天是周日和周一,但同一周的周二到周六是 2013 年。你需要决定这是两个单独的星期,还是那是同一周。

但是(SMALLINT 与 DATE 的)节省 1 字节并不是真正的好处。“week_id”列让你(如我所见)是你有一个标识一周的 id 值。考虑,的日期值'2012-07-30',它们实际上都代表同一周。所以你有多个一周的值,这样一个 UNIQUE 约束并不能真正保证(在数据库方面)你在同一周没有超过行。(这当然不是一个无法克服的问题,您可以指定只存储一个星期日(或星期一)的日期值。)'2012-07-31''2012-08-01'(product_id,date)


总之,

为了节省空间,我将首先删除该代理id列,并将 product_id 和 DATE 的组合作为主键。

然后我只会考虑将该 DATE 更改为 SMALLINT,如果我可以保证所有查询都将引用该裸 SMALLINT 列,而不是引用将 SMALLINT 列转换回 DATE 的表达式。

于 2012-07-30T16:19:48.860 回答