我正在考虑桌面设计的两种选择,我不确定每种选择的优缺点。
以下是对我的情况的抽象描述:
我正在跟踪多个数据点(category_id, point_id, value)
。
大多数时候,我只对数据点的当前值感兴趣。但是我需要在发生变化时记录所有历史值。
偶尔我可能想查看特定点的历史值,但如果这些查询有点慢,则可以。最重要的是,我可以尽快获得所有点的当前值,或特定类别中所有点的当前值。
我正在考虑的两种(可能是三种)方法:
current_vales
和history
表,每次current_values
中的某些内容发生更改时,触发器会在历史记录表中插入一行。 isCurrent
的表。只要值发生更改,就会将该行标记为不再是当前行,并插入具有更新值的新当前行。一次只有大约3,000-5,000个当前点,但是这些值经常变化很多,其中一半可以每天都在变化,因此最终会有数十万行历史记录。
上述每种方法的优缺点是什么(或者还有其他更好的方法,我没有提及)?鉴于我的目标是尽快获得当前的点数,并且对历史记录的查询速度较慢,这是最好的吗?
答案 0 :(得分:1)
选项1和2将具有相似的性能 - 选项1中数据的手动“分区”也可以使用聚簇索引进行管理,其中IsCurrent作为选项2中的第一列。您始终可以拥有仅提供的视图当前以及在某些方面,这将在性能上非常相似,因为更改IsCurrent将物理地移动旧行(由于群集)并添加新行,就像您的触发器将删除并插入两个表中一样。
您还可以使用MySQL的分区功能。
使用单个表的单独表或分区的一大好处是以更细粒度的方式控制数据的备份(并可能清除)。
选项1的一个真正好处是你可以保存那个小列,当你获得数十亿行时这可能是有益的。
选项2的维护优势是架构始终相同(不必保持同步更改),因为只有一个表。
选项3不会表现得那么好,因为当前值的前沿更难以找到 - 即变化(尽管不是不可能通过标识符和时间戳DESC上的索引来提高性能)
答案 1 :(得分:1)
选择当前值
选项1与具有正确索引的选项2大致相同
选项1的示例索引(category_id,point_id)
选项2的示例索引(isCurrent,category_id,point_id)
当您使用选项2表选择时,您需要在where过滤器中包含IsCurrent。数据库引擎将知道索引具有分组的当前记录,甚至不需要查看非当前记录。将该表视为电话簿,如果没有索引,您需要检查每个页面以查找您所追求的业务。但是使用索引,您可以查找索引,并且它表示以“H”开头的商家位于第348页。因此,您可以直接转到第348页并忽略其他内容。它与数据库的概念相同,只有你能够创建嵌套的索引级别。 对于咆哮感到抱歉,但有些人表示选项2的速度要慢得多,但事实并非如此。
<强>插入/更新。强>
这是我看到选项1和2之间的主要区别。
选项1,当您对现有记录进行更新时,这些是我看到的步骤
选项2,当您对现有记录进行更新时,这些是我看到的步骤
您点击磁盘的次数越多,获得的速度就越慢。在你每分钟进行大量更新之前,这可能不是什么大问题,但是数据库需要做的工作越少越好。
我已经将选项3留下了,因为它不容易在没有粉碎磁盘的情况下获取当前记录。我认为无论你选择哪个选项,你都需要时间戳,但只有在查询历史数据时,比如一个值有20个历史值,你会显示20个中的哪一个?
这是我的两位价值。
答案 2 :(得分:0)
我会选择#1选项。它允许轻松检索current_values,历史表将包含大量事务,但如有必要,可能会清除旧历史记录。
选项#2会让你更经常地查询current_values,返回的速度要慢得多。
答案 3 :(得分:0)
选项1似乎是正确的方法,因为迁移到历史的更改更多是审计。它也更好地分离数据。
选项2:当表示的行是唯一的时,使用同一表中的多行。因此,鉴于改变将在一个独特的实体上进行,最好不要从设计的角度来看它。
选项3:选项2中的评论再次适用&amp;查询也可能陷入困境。