SQL Server RowVersion/时间戳 - 比较

Posted

技术标签:

【中文标题】SQL Server RowVersion/时间戳 - 比较【英文标题】:SQL Server RowVersion/Timestamp - Comparisons 【发布时间】:2011-05-27 03:05:24 【问题描述】:

我知道RowVersion 列的值本身并没有用,除了每次更新行时它都会改变。但是,我想知道它们是否对相对(不等式)比较有用。

如果我有一个包含RowVersion 列的表,那么以下情况是否属实:

所有同时发生的更新(相同的更新语句或相同的事务)在RowVersion 列中是否具有相同的值? 如果我先更新“A”,然后更新“B”,更新“B”中涉及的行的值是否会高于更新“A”中涉及的行?

谢谢。

【问题讨论】:

【参考方案1】:

请注意,timestamp 在 SQL Server 2008 及以后版本中已弃用。应该改用rowversion

来自 MSDN 上的this page:

timestamp 语法已弃用。此功能将在 Microsoft SQL Server 的未来版本。避免在 新的开发工作,并计划修改当前的应用程序 使用此功能。

【讨论】:

但是如果我执行CREATE TABLE TBL(PriKey int PRIMARY KEY, VerCol rowversion) ; VerCol的数据类型是timestamp!有什么意义?! 令人讨厌的是,SSMS 不会将 rowversion 识别为有效的数据类型,只有时间戳 至少 Redmond 的脚本小子的主管介入并在一个版本之后才取消了“时间戳”概念。希望孩子们在被要求在字典中查找“时间”和“时间戳”这两个词后被解雇。在回家的路上,他们会发现他们的时间戳没有关于时间的信息,并想知道他们是否有希望在其他地方找到工作。【参考方案2】:

我花了很长时间试图解决这个问题 - 要求在特定序列号之后更新列。时间戳实际上只是一个序列号 - 当像 BitConverter.ToInt64 这样的 c# 函数需要 littleendian 时,它也是 bigendian。

我最终在表上创建了一个数据库视图,我希望使用别名列“SequenceNo”从中获取数据

SELECT     ID, CONVERT(bigint, Timestamp) AS SequenceNo
FROM         dbo.[User]

c#代码首先看到视图(即UserV)与普通表相同

然后在我的 linq 中,我可以加入视图和父表并与序列号进行比较

var users =  (from u in context.GetTable<User>()
                join uv in context.GetTable<UserV>() on u.ID equals uv.ID
                where mysequenceNo < uv.SequenceNo
                orderby uv.SequenceNo
                select u).ToList();

得到我想要的 - 自上次检查以来所有条目都发生了变化。

【讨论】:

正在寻找对这个概念的验证。 唯一的问题是 rowversion 本质上是一个未签名的 bigint,它在 SQLServer afaik 中不存在。因此,一旦超过最大签名 bigint,CONVERT 就不会真正做你想做的事。 @matt 如果最大数字是 9,223,372,036,854,775,807 我不会太担心在时间戳列中达到它【参考方案3】:

回答您的部分问题:根据 MSDN,您最终可能会得到重复的值:

可以使用 SELECT INTO 生成重复的 rowversion 值 rowversion 列在 SELECT 列表中的语句。我们的确是 不建议以这种方式使用 rowversion。

来源:rowversion (Transact-SQL)

【讨论】:

【参考方案4】:

每个数据库都有一个计数器,每次在数据库中进行数据修改时,计数器都会递增。如果包含受影响(通过更新/插入)行的表包含时间戳/行版本列,则数据库的当前计数器值存储在更新/插入记录的该列中。

【讨论】:

【参考方案5】:

一些附加信息。 RowVersion 可以很好地转换为 bigint,因此可以在调试时显示更好的可读输出:

CREATE TABLE [dbo].[T1](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
    [RowVer] [timestamp] NOT NULL
) 

insert into t1 ([value]) values ('a')
insert into t1 ([value]) values ('b')
insert into t1 ([value]) values ('c')
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1
update t1 set [value] = 'x' where id = 3
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1
update t1 set [value] = 'y' 
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1

Id  Value   RowVer
1   a   2037
2   b   2038
3   c   2039

Id  Value   RowVer
1   a   2037
2   b   2038
3   x   2040

Id  Value   RowVer
1   y   2041
2   y   2042
3   y   2043

【讨论】:

您的示例显示时间戳但在您的陈述中谈论行版本是否正常? timestamp 是 MSSQL 上 rowversion 数据类型的同义词。但时间戳语法已被弃用,并在 Microsoft SQL Server 的未来版本中被删除。【参考方案6】:

Rowversion 确实打破了 SQL 的“理想主义”方法之一 - UPDATE 语句是一个单一的原子操作,并且就像所有 UPDATE(对一行中的所有列和表中的所有行)都发生一样“同时”。但在这种情况下,使用 Rowversion,可以确定某一行的更新时间与另一行略有不同。

请注意,不能保证更新行的顺序(通过单个更新语句) - 碰巧它可能遵循与表的聚集键相同的顺序,但我不会指望这是真的.

【讨论】:

【参考方案7】:

From MSDN:

每个数据库都有一个计数器,每次插入或更新操作都会增加一个计数器,该操作是在数据库中包含rowversion 列的表上执行的。这个计数器是数据库rowversion。这跟踪数据库中的相对时间,而不是可以与时钟关联的实际时间。 每次一行带有rowversion被修改或插入递增数据库rowversion 被插入到rowversion 列中。

http://msdn.microsoft.com/en-us/library/ms182776.aspx

据我了解,系统中实际上并没有同时发生任何事情。这意味着所有rowversions 都应该是唯一的。我冒昧地说,如果在同一个表中允许重复,它们实际上将毫无用处。同样值得信赖的是 rowversions 不被复制是 MSDN 不将它们用作主键的立场,不是因为它会导致违规,而是因为它会导致外键问题。 根据 MSDN,“rowversion 数据类型只是一个递增的数字......”所以是的,后来更大。

对于增加多少的问题,MSDN 指出,“[rowversion] 跟踪数据库中的相对时间”,这表明它不是流体整数增量,而是基于时间的.然而,这个“时间”并没有显示确切的时间,而是相对于其他行插入/修改了一行。

【讨论】:

Brad:但是“后来意味着更大”跨多行,而不仅仅是同一行?从措辞上看,它似乎表示不,但实验似乎意味着是。 @Davied,rowversion 的基础是基于数据库的,这意味着该值在某种程度上与数据库过去的某个点相关。是的,稍后意味着整个数据库更大。将其视为数据库范围的标识值。【参考方案8】:

是什么让您认为 Timestamp 数据类型是邪恶的?数据类型对于并发检查非常有用。 Linq-To-SQL 正是出于这个目的使用这种数据类型。

您的问题的答案:

1) 否。每次更新行时都会更新此值。如果您将行更新五次,则每次更新都会增加 Timestamp 值。当然,您意识到“同时发生”的更新实际上不会。它们仍然一次只出现一次。

2) 是的。

【讨论】:

您的答案#1 似乎暗示我的第二个问题的答案应该是不,不是。如果该值确实只是一个增量,那么为了简单起见,我有值 1、3 和 8 的行。(是的,我知道实际上这些将是 8 字节数组。)不是更新的值如果它们只是增加,是 2、4 和 9,而不是它们都是 9?这意味着后续更新的行(初始值为 5)将变为 6 而不是 9,后者小于原始值。 @David - 你把这弄得太复杂了。每次更新包含 Timestamp 列的行时,该 Timestamp 列中的值都会增加。我不知道如何,也不知道多少。我只知道它增加了。因此,如果“A”更新,然后“B”更新,则在“B”更新后,Timestamp 列中的值将大于“A”的值。 Randy:这对我来说没有意义,但我可能把它弄得太复杂了。如果它是一个简单的增量,并且两行都以相同的值开始,那么更新 A 行,然后更新 B 行,它们不应该有 same 时间戳吗(两者都应该是 1 + 原始) 而不是 B 的价值高于 A? @David - 好吧,假设您正在更新“A”和“B”,并且它们都具有相同的时间戳值。更新“A”后,SQL Server 增加了该行中的值。现在它们不再相等(“A”实际上大于更新前“B”中的值)。现在你更新'B'。 SQL Server 根据“A”更新后的列中的值而不是“B”中的原始值再次增加该值。在“B”更新后,该行中的值大于“A”更新后的值。

以上是关于SQL Server RowVersion/时间戳 - 比较的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用实体框架将 SQL Server 的 rowversion 类型映射到比 byte[] 更友好的东西?

RowVersion 用法

RowVersion数据类型

Windows Phone 7 SQL Server CE 行版本

用于更改跟踪问题的 SQL RowVersion 编号列

SQL MIN_ACTIVE_ROWVERSION() 值长时间不变