【问题标题】: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?当 SQL Server 中的表具有较大的 nvarchar(例如 nvarchar(2000))时,当行存储在页面中时,是否存储了所有 4000 个字节?
【发布时间】:2017-09-04 13:27:33
【问题描述】:

我正在调整一个审计方案:https://weblogs.asp.net/jongalloway/adding-simple-trigger-based-auditing-to-your-sql-server-database,它要求创建一个这样的审计表:

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 表中的每一行。就我而言,我可以缩短TableNamePrimaryKeyFieldPrimaryKeyValueFieldName 的宽度,因为我知道这些东西的实际最大长度。我有一个特定的表,它的特定列定义为 nvarchar(2000),所以如果我继续使用这种通用方法,我需要将 nvarchar(2000) 用于 OldValueNewValue

我想知道关于页面中实际使用的存储空间的 SQL Server 内部优化。当使用 long varchars 或 nvarchars 存储行时,是实际用于将行存储在页面中的完整定义长度,还是 SQL Server 仅存储实际使用的字节。比如上面OldValue中只存储了Hello!,那么OldValue在页面中实际占用多少字节呢?

【问题讨论】:

    标签: sql-server sql-server-performance


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢 SqlZim 的快速回复!那么为什么 SQL Server 会打扰nvarchar(N) 呢?我了解 nvarchar(N) 的页内存储(其中 N nvarchar(max) 的大型对象存储之间的区别,但为什么不只使用 nvarchar(4000) 和 nvarchar(max) 以保持简单? SQL Server 内部是否有一些额外的优化可以使nvarchar(100)nvarchar(4000) 更高效?
    • nvarchar(max) 的处理方式不同,即使作为变量也会对性能产生重大影响,因为它最多支持 2gb 的数据。为 nvarchar() 使用较小的最大值 (N) 将对估算内存授予的计算产生影响。还需要考虑索引键宽度:Maximum Size of Index Keys
    【解决方案2】:

    当使用 long varchars 或 nvarchars 存储行时,是实际用于在页面中存储该行的完整定义长度,还是 SQL Server 仅存储实际使用的字节

    即使你定义了一个可变长度的列,SQL 也会只为声明的值使用存储空间..

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

    以下是马丁·史密斯回答的相关部分

    所有 varchar 数据都存储在行尾的可变长度部分(如果行不下,则存储在 offrow 页面中)。它在该部分中消耗的空间量(以及它是否最终离开行)完全取决于实际数据的长度而不是列声明

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

    create table dbo.test1
    
    (
    fixedlencol varchar(400),
    varlengthcol varchar(max),
    var_len_Nvarcahrcol nvarchar(max)
    )
    
    insert into dbo.test1
    values
    ('a','abc','def')
    

    现在如果按照这里的示例使用 DBCC PAGE 和 DBCC IND:存储引擎内部:Using DBCC PAGE and DBCC IND to find out if page splits ever roll back

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

    插槽 0 列 1 偏移量 0xf 长度 1 长度(物理)1

    fixedlencol = a

    varlengthcol = [BLOB Inline Data] Slot 0 Column 2 Offset 0x10 Length 3 长度(物理)3

    varlengthcol = 0x616263

    var_len_Nvarcahrcol = [BLOB Inline Data] Slot 0 Column 3 Offset 0x13 长度 6 长度(物理)6

    最后一列占用比实际长度双字节的原因是由于 Nvarchar..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-10
      • 2011-08-09
      • 2016-12-24
      • 1970-01-01
      • 1970-01-01
      • 2016-09-24
      相关资源
      最近更新 更多