【问题标题】:Adding a nullable rowversion column to a table向表中添加可为空的 rowversion 列
【发布时间】:2017-07-02 03:20:51
【问题描述】:

我会保持简短而甜蜜。我正在尝试将rowversion 类型的列添加到现有表中。我的想法是,通过将其添加为NULL,现有行不会被标记时间戳,但可惜它们是。如果是这种行为,那么该列在什么情况下会接受空值?

【问题讨论】:

  • rowversion 只是一个系统内部的二进制计数器 - 在该列中为现有行设置值有什么害处?
  • 从我的测试来看,允许这样做似乎完全没有意义,除了与 CREATE TABLE 语法的兼容性之外,它可能是 sybase 的遗产。 sqlfiddle.com/#!6/6ea10

标签: sql-server rowversion


【解决方案1】:

即使设置为NULL,rowversion也会取值:

CREATE TABLE MyTest (myKey int PRIMARY KEY, myValue int);  
GO   
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);  
GO   
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);  
GO  
SELECT * FROM MyTest;
GO
ALTER TABLE MyTest ADD rv rowversion NULL;
GO
SELECT * FROM MyTest;
GO
DROP TABLE MyTest;

+-------+---------+------------+
| myKey | myValue | rv         |
+-------+---------+------------+
| 1     | 0       | 0000020331 |
+-------+---------+------------+
| 2     | 0       | 0000020332 |
+-------+---------+------------+

在这里查看:http://rextester.com/ENELE48783

【讨论】:

  • 是的。我在问题的陈述中也说了这么多。我的问题是:如果他们让您选择将其设为可空类型,可空与不可空之间的功能区别是什么?
【解决方案2】:

如果他们让您选择将其设为可空类型,可空与不可空之间的功能区别是什么

实际上没有功能差异(但可能存在存储差异,见下文)。您不能将 NULL 插入到 rowversion 列中。

即使您在INSERT 语句中为rowversion 列指定NULL,服务器也会插入生成的非空值。无论您如何声明 rowversion 列(NULLNOT NULL),它都会像这样工作。


docs 只提到一次可以为空的rowversion

不可为空的rowversion 列在语义上等价于 binary(8) 专栏。可为空的 rowversion 列在语义上是 相当于varbinary(8) 列。

如果您指定rowversion 可以为空,它应该在磁盘上占用更多空间以允许存储可能的NULL 值(实际上这不可能发生)。每个可为空的列都会产生开销,请参阅:How much size "Null" value takes in SQL Server

除了存储空值所需的空间之外,还有 具有可为空的列的开销。

此外,varbinary(8)binary(8) 占用更多的磁盘空间来存储值的长度。


说了这么多,我尝试创建两个表,每个表有 10M 行。一个带有可空的 rowversion 列,第二个带有不可空的 rowversion 列。在我的测试中,两个表占用的磁盘空间完全相同。我在 SQL Server 2014 Express 上进行了测试。

【讨论】:

  • 我害怕这个。我试图做的是使用 SQL Server 的行为来添加一个可为空的列作为元数据操作来添加该列。相反,看起来不管列的可空性如何,它仍然是一个“数据大小”操作。真可惜。感谢收看!
  • "varbinary(8)binary(8) 占用更多磁盘空间" 如果你有一个varbinary(8) 但只插入一个1 字节的二进制值,它有多大?根据文档,它是值的长度 + 2 个字节,所以它将是 3 个字节。 binary(8) 始终为 8 个字节。您引用的另一个问题还说“如果字段是可变宽度,则 NULL 值不占用空间”,然后“确实,使列可以为空需要一些存储空间,但是一旦你完成了它需要更少存储 NULL 的空间比存储值所需的空间(对于可变宽度列)。"
  • 如果您无法插入 NULL,那么指定 NULLABLE ROWVERSION 的潜在好处可能是当插入小于 8 字节的 rowversion 值时,它们使用的空间更少。如果不是这种情况,那么它似乎毫无意义,您应该始终使用不可为空的,但我不相信。您如何比较测试中的磁盘大小?也许页面大小相同但页面填充较少,或类似的东西。
  • @Davos,如果我没记错的话,rowversion 的值总是正好是 8 个字节。它不能小于 8 个字节。这就是我说varbinary(8)binary(8) 占用更多磁盘空间的原因。前段时间我做过测试,我不记得细节了。如果你能再做一次测试并向我们展示它的结果,那就太好了。
  • 如果 rowversion 总是插入 8 个字节,那么这对于 rowversion 的情况是有意义的。我会做测试并告诉你,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-25
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多