正确的方法来创建动态1:M SQL表

时间:2014-02-18 00:20:19

标签: sql performance database-design architecture one-to-many

简化示例:两个表 - 人和时间。目标是跟踪一个人走过门口的所有时间。

一个人每天可以在时间表中有0到50个条目。

跟踪这些记录的正确和最有效的方法是什么?是吗

times table
-----------
person_id
timestamp

我担心这张桌子可以很快地获得超过一百万条记录。插入和检索时间至关重要。

另外:显然非标准化但是做一个更好的主意

times table
-----------
person_id
serialized_timestamps_for_the_day
date

我们需要访问此人的每个时间戳,但仅查询日期或人员ID的记录。

3 个答案:

答案 0 :(得分:1)

考虑一下我们在这里谈论什么。仅考虑原始数据(event_time, user_id),这将是每1M行(4 + 4) * 1M ~ 8MB。让我们尝试在DB中粗略估计一下。

一个整数4个字节,时间戳4个字节;行标题,比方说18个字节 - 这会将行大小的第一个估计带到4 + 4 + 18 = 26 bytes。使用页面填充因子约为0.7; ==>

。每行26 / 0.7 ~ 37个字节。

因此,对于1M行,大约37 MB。您需要(user_id, event_time)上的索引,所以我们只需将原始内容翻倍为37 * 2 = 74 MB

这使得非常粗略,无法估计的估计值为每1M行74MB。

因此,要始终将其保留在内存中,此表的每1M行需要0.074 GB。

要获得更好的估算,只需创建一个表,添加索引并用几百万行填充它。

考虑到预期的数据量,即使在笔记本电脑上也可以轻松测试10M行 - 测试总是比较推测。

P.S。您的选项2 看起来“明显更好的主意”我也是。

答案 1 :(得分:1)

第二种解决方案存在一些问题:

  • 由于您需要访问单个时间戳 1 serialized_timestamps_for_the_day不能被视为atomic并且会违反1NF,从而导致bunch of problems
  • 最重要的是,您正在引入冗余:date可以从serialized_timestamps_for_the_day的内容中推断出来,您的应用程序代码需要确保它们永远不会变得“失去同步”,这容易受到错误的影响。 2

因此请选择第一个解决方案。如果properly indexed,现代硬件上的现代数据库可以处理的不仅仅是“超过一百万条记录”。在这个具体案例中:

  • {person_id,timestamp}上的综合索引将允许您通过简单的索引范围扫描查询人或人和日期的组合,这可能非常有效。
  • 如果您只需要“按日期”查询,则需要{timestamp}上的索引。您可以通过搜索指定日期的00:00到24:00范围,轻松搜索特定日期内的所有时间戳。

1 即使您不查询单个时间戳,仍需要逐个将它们写入数据库。如果您有序列化字段,则首先需要读取整个字段以仅附加一个值,然后将整个结果写回数据库,这可能会很快成为性能问题。还有其他问题,如上面的链接所述。

2 作为一般规则,不能存储的内容,除非有良好的表现理由这样做,我不知道看到这里的任何内容。

答案 2 :(得分:0)

我认为第一种选择是更好的选择。

即使您选择第二个选项,索引的大小也不会减少。实际上会有一个额外的专栏。

与不同用户的数据无关,您可以根据person_id对数据库进行分片。即,假设您的数据不适合单个数据库服务器节点,并且需要两个节点。然后,一半用户的数据将存储在一个节点上,其余数据将存储在另一个节点上。

这可以使用像MySQL这样的RDBMS或像MongoDBOrientDB这样的面向文档的数据库来完成。