当 SQL 服务器中的 table 具有较大的 nvarchar(比如 nvarchar(2000))时,当行存储在页面中时,是否存储了所有 4000 个字节?

When a table in SQL Server has a large-ish nvarchar (say nvarchar(2000)) when the row is stored in the page, do all 4000 bytes get stored?

我正在根据此调整审计方案:https://weblogs.asp.net/jongalloway/adding-simple-trigger-based-auditing-to-your-sql-server-database 需要创建审计 table,如下所示:

CREATE TABLE Audit
(
AuditID [int]IDENTITY(1,1) NOT NULL,
Type char(1), 
TableName varchar(128), 
PrimaryKeyField varchar(1000), 
PrimaryKeyValue varchar(1000), 
FieldName varchar(128), 
OldValue varchar(1000), 
NewValue varchar(1000), 
UpdateDate datetime DEFAULT (GetDate()), 
UserNamevarchar(128)
)

我想确保为插入 Audit table 的每一行存储尽可能少的数据。就我而言,我可以缩短 TableNamePrimaryKeyFieldPrimaryKeyValueFieldName 的宽度,因为我知道这些东西的实际最大长度。我有一个特定的 table,它有一个定义为 nvarchar(2000) 的特定列,所以如果我继续使用这种通用方法,我将需要对 OldValue 和 [=19= 使用 nvarchar(2000) ].

我想知道 SQL 服务器关于页面实际使用的存储 space 的内部优化。当一行以 long varchars 或 nvarchars 存储时,是实际用于在页面中存储该行的完整定义长度,还是 SQL 服务器仅存储实际使用的字节数。比如上面的OldValue中只存储了Hello!,那么这样一行OldValue实际在页中占多少字节?

对于nvarchar(N),该值的行中存储的最大字节数为2 + (2*N)。前 2 个是长度,然后是实际存储在行中的每个 unicode 字符 2 个字节。这是占用的最大值space。

如果您的 unicode 字符串只有 15 个字符,那么它将是 32 个字节(即使是 nvarchar(2000) 数据类型)。

我还建议使用 sysname 作为系统对象的名称,以便在您的脚本中实现向前(和向后)兼容性。

您可能也对此审核脚本感兴趣:Quick And Easy Audit Tables - Dave Britten

When a row is stored with long varchars or nvarchars, is the full defined length actually used to store the row in a page, or does SQL Server only store the actual bytes used

即使您定义了一个可变长度的列,SQL 也会将存储 space 仅用于声明的值..

这里已经介绍过了:How are varchar values stored in a SQL Server database?

以下是 Martin Smith 的回答中的相关部分

All varchar data is stored at the end of the row in a variable length section (or in offrow pages if it can't fit in row). The amount of space it consumes in that section (and whether or not it ends up off row) is entirely dependant upon the length of the actual data not the column declaration

下面是一个示例演示来证明这一点

create table dbo.test1

(
fixedlencol varchar(400),
varlengthcol varchar(max),
var_len_Nvarcahrcol nvarchar(max)
)

insert into dbo.test1
values
('a','abc','def')

现在,如果按照 here:Inside 存储引擎中的示例使用 DBCC PAGE 和 DBCC IND:Using DBCC PAGE and DBCC IND to find out if page splits ever roll back

下面是输出,我在第一行插入

Slot 0 Column 1 Offset 0xf Length 1 Length (physical) 1

fixedlencol = a

varlengthcol = [BLOB Inline Data] Slot 0 Column 2 Offset 0x10 Length 3 Length (physical) 3

varlengthcol = 0x616263

var_len_Nvarcahrcol = [BLOB Inline Data] Slot 0 Column 3 Offset 0x13 Length 6 Length (physical) 6

最后一列比实际长度多出双字节的原因是 Nvarchar..