Sql 数字数据类型-存储

Sql 数字数据类型-存储,sql,sql-server,Sql,Sql Server,根据数字(10,2)-10类型的数据,表示精度应为9字节 但当我这么做的时候: DECLARE @var as numeric(10,0) = 2147483649 SELECT @var, DATALENGTH(@var) DATALENGTH(@var)返回的是5字节,而不是10字节。有人能解释一下原因吗?文档规定: 最大存储大小因精度而异 对于给定的精度,存储不是恒定的。实际存储取决于该值 值得注意的是,这与整体性无关。下面还返回5: declare @var numberic(11,

根据数字(10,2)-10类型的数据,表示精度应为9字节

但当我这么做的时候:

DECLARE @var as numeric(10,0) = 2147483649

SELECT @var, DATALENGTH(@var)

DATALENGTH(@var)返回的是5字节,而不是10字节。有人能解释一下原因吗?

文档规定:

最大存储大小因精度而异

对于给定的精度,存储不是恒定的。实际存储取决于该值

值得注意的是,这与整体性无关。下面还返回5:

declare @var numberic(11, 1) = 214483649.8
实际上,SQL Server似乎使用了值所需的存储量,而不是类型的最大值。您可以通过将“10”更改为“20”并注意到数据长度没有改变,很容易看到这一点

编辑:

如果运行以下命令,可以看到对值的依赖:

declare @a numeric(20, 1) = '123.1';
declare @b numeric(20, 1) = '1234567890123456789.0';
select datalength(@a), datalength(@b);

这两种长度不相同。

文档规定:

最大存储大小因精度而异

对于给定的精度,存储不是恒定的。实际存储取决于该值

值得注意的是,这与整体性无关。下面还返回5:

declare @var numberic(11, 1) = 214483649.8
实际上,SQL Server似乎使用了值所需的存储量,而不是类型的最大值。您可以通过将“10”更改为“20”并注意到数据长度没有改变,很容易看到这一点

编辑:

如果运行以下命令,可以看到对值的依赖:

declare @a numeric(20, 1) = '123.1';
declare @b numeric(20, 1) = '1234567890123456789.0';
select datalength(@a), datalength(@b);

这两个长度不一样。

另一个答案是@GordonLinoff的错误,或者至少是误导。
Numeric
不是以可变的字节数存储的,而是以固定的大小存储特定的精度

在SQL Server 2017上尝试此操作会得到与您相同的结果

您最初链接到的文档,例如
numeric
,关于存储不同精度的数字所需的字节数是正确的

此存储要求仅基于
数值列的精度。换句话说,这就是使用了多少字节的存储空间。它不是取决于该行中的值的最大值。
所有行对该列使用相同的字节数

此变化的关键是
DATALENGTH
说明此函数的文档

看来,
DATALENGTH
的意思并不像磁盘上的“表示”那样是“表示”,而是内存中的“表示”。 另一篇关于
numeric
的文档是关于
numeric
的磁盘存储

这可能是因为
DATALENGTH
主要用于var*类型或其他BLOB类型

因此,尽管一个
数值(20,1)
需要13个字节的存储空间,但根据值的不同,SQL Server可以在内存中以较小的字节数表示它,也就是在
DATALENGTH
计算它时

正如我在另一篇评论中指出的,尽管
numeric
有不同的大小,但它是一种固定大小的数据类型,因为对于特定表中的特定列,每个值占用相同的存储量

大致上,SQL Server行包含4个部分:

  • 4字节头
  • 固定大小数据
  • 将偏移量转换为可变大小的数据
  • 可变大小数据
  • 数字和其他固定大小类型存储在2中,
    var*
    存储在4中,长度存储在3中

    此脚本显示具有某些固定和可变列的表的元数据

    declare @a numeric(20, 1) = '123.1';
    declare @b numeric(20, 1) = '1234567890123456789.0';
    select datalength(@a) union select datalength(@b);
    
    create table #numeric(num1 numeric(20,1), text1 varchar(10), char2 char(6));
    insert into #numeric(num1, text1, char2) values ('123.1', 'hello', 'first'), ('1234567890123456789.0', 'there', '2nd');
    
    select datalength(num1) from #numeric;
    
    select
        t.name as table_name,
        c.name as column_name,
        pc.partition_column_id,
        pc.max_inrow_length,
        pc.max_length,
        pc.precision,
        pc.scale,
        pc.collation_name,
        pc.leaf_offset
    from tempdb.sys.tables as t
    join tempdb.sys.partitions as p
        on(t.object_id=p.object_id)
    join tempdb.sys.system_internals_partition_columns as pc
        on(pc.partition_id=p.partition_id)
    join tempdb.sys.columns as c
        on((c.object_id=p.object_id)and(c.column_id=pc.partition_column_id))
    where (t.object_id=object_id('tempdb..#numeric'));
    
    drop table #numeric;
    
    请注意
    leaf\u offset
    列。这表示值在原始二进制数据中的起始位置。 第一列在4字节头之后立即开始。 根据SQL文档,第二个固定列在13字节之后开始。
    varchar
    列的偏移量为-1,表示它是一个可变长度的列&它在字节数组中的位置不是固定的。 在这种情况下,它可能是固定的,因为只有一个var列,但是
    altertable
    语句可以添加另一个列&移位


    如果您想进一步研究,最好的资料来源是卡伦·德莱尼(Kalen Delaney)的一本名为《SQL Server内部结构》的书。她是编写SQL Server的团队的一员。

    另一个由@GordonLinoff给出的答案是错误的,或者至少是误导性的。
    Numeric
    不是以可变的字节数存储的,而是以固定的大小存储特定的精度

    在SQL Server 2017上尝试此操作会得到与您相同的结果

    您最初链接到的文档,例如
    numeric
    ,关于存储不同精度的数字所需的字节数是正确的

    此存储要求仅基于
    数值列的精度。换句话说,这就是使用了多少字节的存储空间。它不是取决于该行中的值的最大值。
    所有行对该列使用相同的字节数

    此变化的关键是
    DATALENGTH
    说明此函数的文档

    看来,
    DATALENGTH
    的意思并不像磁盘上的“表示”那样是“表示”,而是内存中的“表示”。 另一篇关于
    numeric
    的文档是关于
    numeric
    的磁盘存储

    这可能是因为
    DATALENGTH
    主要用于var*类型或其他BLOB类型

    因此,尽管一个
    数值(20,1)
    需要13个字节的存储空间,但根据值的不同,SQL Server可以在内存中以较小的字节数表示它,也就是在
    DATALENGTH
    计算它时

    正如我在另一篇评论中指出的,尽管
    numeric
    有不同的大小,但它是一种固定大小的数据类型,因为对于特定表中的特定列,每个值占用相同的存储量

    大致上,SQL Server行包含4个部分:

  • 4字节头
  • 固定大小数据
  • 将偏移量转换为可变大小的数据
  • 可变大小数据
  • N