根据Microsoft Site ,数字类型为Numeric(10,2) - 10表示精度应该有9个字节。
但是当我这样做时:
DECLARE @var as numeric(10,0) = 2147483649
SELECT @var, DATALENGTH(@var)
DATALENGTH(@var)返回5个字节而不是10.有人可以解释为什么吗?
答案 0 :(得分:0)
文档指定:
根据精确度,最大存储容量会有所不同。
对于给定的精度,存储不是常量。实际存储取决于值。
注意,这与整数无关。以下还返回5:
(a + b[:,None])[0,0]
#array([[ 2., 2.],
# [ 2., 2.]])
(a + b[:,None])[0,1]
#array([[ 1., 1.],
# [ 1., 1.]])
(a + b[:,None])[1,0]
#array([[ 1., 1.],
# [ 1., 1.]])
(a + b[:,None])[1,1]
#array([[ 0., 0.],
# [ 0., 0.]])
实际上,SQL Server似乎使用了值所需的存储量,而不是该类型的最大值。您可以通过将“10”更改为“20”并注意数据长度不会改变来轻松看到这一点。
编辑:
如果你运行,你可以看到对价值的依赖:
declare @var numberic(11, 1) = 214483649.8
这两个长度不一样。
答案 1 :(得分:0)
@GordonLinoff的另一个答案是错误的,或者至少是误导性的。
Numeric
不存储可变数量的字节,但具有固定大小的特定精度。
在SQL Server 2017上尝试此操作会得到相同的结果。
您最初为numeric
链接的文档对于存储不同精度的数字所需的字节数是正确的。
此存储要求仅基于numeric
列的精度。换句话说,就是使用了多少字节的存储空间。它不是最大值取决于该行中的值。
所有行对该列使用相同的字节数。
此变体的关键是DATALENGTH
的文档说明了此功能
Returns the number of bytes used to represent any expression.
似乎DATALENGTH
并不代表'代表',就像磁盘上的'代表'一样,而是代表内存中的'代表'。
关于numeric
的其他文档是关于numeric
的磁盘存储。
这可能是因为DATALENGTH
主要用于var *类型或其他BLOB类型。
因此,虽然numeric(20,1)
需要13个字节的存储空间,但根据值,SQL Server可以在内存中以较小的字节数表示它,即DATALENGTH
计算它时。
正如我在其他评论中所指出的,尽管numeric
具有不同的大小,但它是固定大小的数据类型,因为对于特定表中的特定列,每个值占用相同的存储量。 / p>
粗略地说,SQL Server行有4个部分:
Numerics&其他固定大小类型存储在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_offset
列。这表示原始二进制数据中值的起始位置。
第一列在4字节标题后立即开始。
根据SQL文档,第二个固定列在13个字节后启动。
varchar
列的偏移量为-1,表示它是一个可变长度的列&它在字节数组中的位置不固定。
在这种情况下,它可以修复,因为只有1个var列,但alter table
语句可以添加另一个列&转移事物。
如果你想进一步研究,最好的来源是Kalen Delaney的一本名为SQL Server Internals的书。她是编写SQL Server的团队的一员。