双时态 SQL 数据库可能只使用 3 个时间戳吗?
Is using only 3 timestamps for a bitemporal SQL database possible?
在SQL中实现双时态数据库时,通常建议使用以下时间戳:
- 有效开始
- 有效结束
- 交易开始
- 交易结束
我以前曾多次使用过这种方法,但我一直想知道为什么只有 3 个时间戳,而将 TransactionEnd 排除在外,并不是同样正确的实现。这里一个交易时间范围是从TransactionStart到下一个TransactionStart。
对于不仅使用 3 个时间戳会限制数据库的大小,是否有任何强有力的论据?
在一维时态数据库中仅使用一个时间戳而非两个时间戳的示例:
我有一家商店,我想记录用户 X 何时在我的商店。
如果我使用带有开始时间和结束时间的模型,此信息可以记录为
X,1,2
X,3,4
所以用户 X 在 1 和 2 之间以及 3 和 4 之间在我的店里。这很清楚,简单明了。
如果我只使用开始时间作为时间戳来建模我的数据,我将有:
X,1
X,2
X,3
X,4
但是我该如何解释这些数据呢?
X 来自 (1,2) 和 X 来自 (3,4)?或来自(2,3)的X和来自(1,4)的X?
或来自 (1,2)、(2,3)、(3,4) 的 X?来自 (4,inf) 的 X 有效吗?
要理解此数据,我需要向我的数据或代码添加额外的 constraints/logic/information:
也许间隔是不重叠的,也许我为每个对象添加了一个 id,等等。
所有这些解决方案并非在所有情况下都有效,可能难以维护和其他问题。
例如:如果我为每个项目添加一个 id(在本例中为 a,b),结果将是:
X,a,1
X,a,2
X,b,3
X,b,4
为了将我的数据存储在 2 行 3 列中,我的数据将存储在 4 行 3 列中。
使用这个模型不仅我没有任何好处,而且这个模型可以简化为:
X,a, 1,2
X,b, 3,4
进一步缩减为
X, 1,2
X, 3,4
如评论中所述,这是为了简单起见,因为没有它进行某些查询会有些困难。
考虑以下示例。 John
于 1990 年 1 月 1 日在某个地点 Location1
出生,但首次登记出生于 5 日。
数据库 table,Persons
,现在看起来是这样的:
+----------+--------------+------------+----------+------------+----------+
| Name | Location | valid_from | valid_to | trans_from | trans_to |
+----------+--------------+------------+----------+------------+----------+
| John | Location1 | 01-01-1990 |99-99-9999| 05/01/1990 |99-99-9999|
+----------+--------------+------------+----------+------------+----------+
此时,删除 trans_to
列不会造成太大麻烦,但假设如下:
几年后,比如 20 年,John
搬迁到 Location2
,并在 20 天后通知官员。
这将使 Persons
table 看起来像这样
+----------+--------------+------------+----------+------------+----------+
| Name | Location | valid_from | valid_to | trans_from | trans_to |
+----------+--------------+------------+----------+------------+----------+
| John | Location1 | 01-01-1990 |99-99-9999| 05/01/1990 |20-01-2010|
| John | Location1 | 01-01-1990 |01-01-2010| 20/01/2010 |99-99-9999|
| John | Location2 | 01-01-2010 |99-99-9999| 20/01/2010 |99-99-9999|
+----------+--------------+------------+----------+------------+----------+
假设有人想找出"Where does the system think John is living now"(交易时间),而不管他实际上住在哪里。这可以(大致)在 SQL 中通过以下方式查询
Select Location
From Persons
Where Name = John AND trans_from > NOW AND trans_to < NOW
假设删除了交易结束时间
+----------+--------------+------------+----------+------------+
| Name | Location | valid_from | valid_to | trans_from |
+----------+--------------+------------+----------+------------+
| John | Location1 | 01-01-1990 |99-99-9999| 05/01/1990 |
| John | Location1 | 01-01-1990 |01-01-2010| 20/01/2010 |
| John | Location2 | 01-01-2010 |99-99-9999| 20/01/2010 |
+----------+--------------+------------+----------+------------+
上面的查询当然不再有效,但是在最后一个 table 中为相同的查询制定逻辑会有些困难。由于缺少 trans_to
,因此必须从 table 中的其他行派生。例如,第一行的隐式 trans_to
时间(从最旧的条目开始)是第二行的 trans_from
,这是两行中较新的。
事务结束时间因此是 9999-99-99
,如果该行是最新的, 或 它是紧接其后的行的 trans_from
。
这意味着关于特定行的数据并没有完全保存在该行中,并且行之间形成了相互依赖性,这(当然)是不需要的。此外,很难确定哪一行是某行的直接后继行,这会使查询更加复杂
在SQL中实现双时态数据库时,通常建议使用以下时间戳:
- 有效开始
- 有效结束
- 交易开始
- 交易结束
我以前曾多次使用过这种方法,但我一直想知道为什么只有 3 个时间戳,而将 TransactionEnd 排除在外,并不是同样正确的实现。这里一个交易时间范围是从TransactionStart到下一个TransactionStart。
对于不仅使用 3 个时间戳会限制数据库的大小,是否有任何强有力的论据?
在一维时态数据库中仅使用一个时间戳而非两个时间戳的示例:
我有一家商店,我想记录用户 X 何时在我的商店。
如果我使用带有开始时间和结束时间的模型,此信息可以记录为
X,1,2
X,3,4
所以用户 X 在 1 和 2 之间以及 3 和 4 之间在我的店里。这很清楚,简单明了。
如果我只使用开始时间作为时间戳来建模我的数据,我将有:
X,1
X,2
X,3
X,4
但是我该如何解释这些数据呢? X 来自 (1,2) 和 X 来自 (3,4)?或来自(2,3)的X和来自(1,4)的X? 或来自 (1,2)、(2,3)、(3,4) 的 X?来自 (4,inf) 的 X 有效吗?
要理解此数据,我需要向我的数据或代码添加额外的 constraints/logic/information: 也许间隔是不重叠的,也许我为每个对象添加了一个 id,等等。 所有这些解决方案并非在所有情况下都有效,可能难以维护和其他问题。
例如:如果我为每个项目添加一个 id(在本例中为 a,b),结果将是:
X,a,1
X,a,2
X,b,3
X,b,4
为了将我的数据存储在 2 行 3 列中,我的数据将存储在 4 行 3 列中。 使用这个模型不仅我没有任何好处,而且这个模型可以简化为:
X,a, 1,2
X,b, 3,4
进一步缩减为
X, 1,2
X, 3,4
如评论中所述,这是为了简单起见,因为没有它进行某些查询会有些困难。
考虑以下示例。 John
于 1990 年 1 月 1 日在某个地点 Location1
出生,但首次登记出生于 5 日。
数据库 table,Persons
,现在看起来是这样的:
+----------+--------------+------------+----------+------------+----------+
| Name | Location | valid_from | valid_to | trans_from | trans_to |
+----------+--------------+------------+----------+------------+----------+
| John | Location1 | 01-01-1990 |99-99-9999| 05/01/1990 |99-99-9999|
+----------+--------------+------------+----------+------------+----------+
此时,删除 trans_to
列不会造成太大麻烦,但假设如下:
几年后,比如 20 年,John
搬迁到 Location2
,并在 20 天后通知官员。
这将使 Persons
table 看起来像这样
+----------+--------------+------------+----------+------------+----------+
| Name | Location | valid_from | valid_to | trans_from | trans_to |
+----------+--------------+------------+----------+------------+----------+
| John | Location1 | 01-01-1990 |99-99-9999| 05/01/1990 |20-01-2010|
| John | Location1 | 01-01-1990 |01-01-2010| 20/01/2010 |99-99-9999|
| John | Location2 | 01-01-2010 |99-99-9999| 20/01/2010 |99-99-9999|
+----------+--------------+------------+----------+------------+----------+
假设有人想找出"Where does the system think John is living now"(交易时间),而不管他实际上住在哪里。这可以(大致)在 SQL 中通过以下方式查询
Select Location
From Persons
Where Name = John AND trans_from > NOW AND trans_to < NOW
假设删除了交易结束时间
+----------+--------------+------------+----------+------------+
| Name | Location | valid_from | valid_to | trans_from |
+----------+--------------+------------+----------+------------+
| John | Location1 | 01-01-1990 |99-99-9999| 05/01/1990 |
| John | Location1 | 01-01-1990 |01-01-2010| 20/01/2010 |
| John | Location2 | 01-01-2010 |99-99-9999| 20/01/2010 |
+----------+--------------+------------+----------+------------+
上面的查询当然不再有效,但是在最后一个 table 中为相同的查询制定逻辑会有些困难。由于缺少 trans_to
,因此必须从 table 中的其他行派生。例如,第一行的隐式 trans_to
时间(从最旧的条目开始)是第二行的 trans_from
,这是两行中较新的。
事务结束时间因此是 9999-99-99
,如果该行是最新的, 或 它是紧接其后的行的 trans_from
。
这意味着关于特定行的数据并没有完全保存在该行中,并且行之间形成了相互依赖性,这(当然)是不需要的。此外,很难确定哪一行是某行的直接后继行,这会使查询更加复杂