在批量数据上执行时,使用ALTER提高列的精度是否会影响数据库性能?

CIP*_*HER 9 sql sql-server alter-table sql-server-2008

我在一个实时数据库中有一个SQL表,它有超过600万行,我想提高特定列的精度:

ALTER TABLE sales ALTER COLUMN amount DECIMAL(8,4)
Run Code Online (Sandbox Code Playgroud)

现在我的问题是,如果我执行上面的查询,SQL Server会重新计算每个单元格并将新值写回到同一个单元格中吗?(如果是,那意味着它肯定需要很长时间才能执行,而我们在数据库上的其他活动也会受到影响.)或者,该语句是否会以其他方式执行?

md4*_*md4 6

快速纠正

转换为decimal(8, 2)to decimal(8, 4)实际上并没有提高精度 ; 它正在增加规模.

十进制/数字 - TSQL:

  • precision(小数)小数点左侧和右侧可存储的最大小数位数.
  • scale可以存储在小数点右侧的最大小数位数.比例必须是从0到p的值.

因此,总的位数(因此,存储要求)没有改​​变.

答案

如果你有超过9999.9999的任何值,你将会遇到算术溢出错误的错误时间.要容纳所有可能的(8,2)值,您需要增加列decimal(10, 4).

但是,这会增加列的存储要求,从5到9个字节.因此,这相当于update对可用性和事务日志的影响的声明.

我在测试中发现的是,至少对于SQL Server 2008R2,如果存储要求发生变化,增加的精度只会导致数据更新.基本上,如果列的新精度值与前一个相同的存储(或更小,并且没有发生截断)大小类别,则表数据不受影响.

对于600万行表,对事务日志的影响大约为2.5GB.它不一定会增长这个数量,但这将消耗多少空间.我的测试使用了大约200万行,该alter语句导致日志从1MB增长到~850MB.

至于对性能的影响(需要多长时间),不知道有关服务器硬件和负载的任何信息,这是不可能的.如果您非常担心要避免修改表,那么最好的方法可能是表交换:

sales_tmp使用所需的架构创建一个新表(),并复制数据:

insert sales_tmp
select * from sales;
Run Code Online (Sandbox Code Playgroud)

如果可以确保sales在操作期间不会修改表,则不必担心使用事务和锁来阻止它.否则,repeatable read事务就足够了,并且至少sales在操作期间不会阻止对表的读取.

然后:

  1. 在新表上复制权限
  2. 重新创建索引和外键引用
  3. 放旧桌子
  4. 重命名新(sales_tmpsales)

如果您在受影响的表上设置了复制或其他奇特的东西,这可能会有一些问题.遗憾的是,禁用和重新启用这些并非易事.

交易日志

如果您担心更新600万条记录对事务日志的影响,则需要批量更新记录.其大小将根据您的需要而有所不同.我会推荐1,000-10,000.

IMO,我认为你真的不需要担心这个问题,除非你的数据库服务器真的受到空闲空间的限制,但这些信息可能对未来有用.

如果您的恢复模型是SIMPLE,那么日志包含也是如此.如果它是全的,事情就更难了.

尽管Blam在他的回答中声称,他的循环实现绝对不能保证任何包含事务日志文件.

SIMIPLE恢复

checkpoint在循环体的末尾发出语句以确保刷新日志数据.SQL Server会定期执行此操作,在大多数情况下您不会注意到,但在某些情况下,您会注意到.下面是高度简化的psudeocode:

while @rows_left > 0
begin
    -- update/copy rows
    checkpoint;
end
Run Code Online (Sandbox Code Playgroud)

满血复活

这比较棘手,因为日志会无限增长,直到您进行日志备份,这会将日志页面标记为非活动状态,并使SQL Server能够重新使用已为日志文件分配的空间.除了推荐一些资源之外,我不会详细讨论这个问题:

  • 对于类似的精度规格,@ Blam的物理表示可能相同.这个答案不是基于证据. (2认同)