减少varchar列的大小对数据库文件有什么影响?


15

我们数据库中有许多表,这些VARCHAR(MAX)表中的列VARCHAR(500)(或比max小得多)足以满足需要。自然,我想清理它们,并将尺寸减小到更合理的水平。我了解的“方法”是:我的问题是更改这些列会对磁盘上​​的页面和现存内容产生什么影响?(那里有很多关于增长一列时会发生什么的信息,但是很难找到收缩一列时会发生什么的信息。)

有些表的行数非常小,因此我不担心更改的成本,但有些表却很大,并且担心它们可能会被重组并导致大量阻塞/停机。实际上,我只想一种估计维护时段的方法。通常,我想更好地了解这种情况下数据库引擎的行为。

提前致谢!

编辑:

我正在查看20个表,尽管其中只有一半的行数大于1,000。最大的行将近一百万行。犯规最严重的是一张有350,000行和4 VARCHAR(MAX)列的表,可以缩小到该VARCHAR(500)水平。

Answers:


12

首先,表中有多少数据?表的行数和大小?

第二:您是否可以备份该表并将其还原到测试服务器,并运行alter语句以查看影响(假设由于表太大而无法在非生产系统上使用该表,因此这是不可行的)?我总是发现,在我的环境中进行测试比通过网络发布的建议更准确,因为存在一些可能会影响结果的因素,而这些因素可能是由于不知道这些因素可能会影响结果而无法在问题中提供的。

第三:增加可变长度字段的大小一个简单的元数据操作(假设您不超过8060字节限制),因为此类操作不会更改实际数据。但是,另一方面,减小可变长度字段的大小,甚至减小到明显更有效的地方,也不是简单的元数据更改,因为SQL Server在扫描所有行之前不知道,则新请求的大小有效。

因此:是,这将锁定表一段时间。多少时间?好吧,这是我刚刚做的测试:

通过其他测试,我得到了一个具有单个INT NOT NULL字段和一百万行的表。我通过以下方式将其复制到新表中:

SELECT *, CONVERT(NVARCHAR(MAX), NEWID()) AS [StringField]
INTO dbo.ResizeTest
FROM dbo.ClusteredUnique;

这样,我从一个类似的场景开始MAX(我刚刚意识到您拥有VARCHAR并且正在使用NVARCHAR,但这不应改变我所看到的行为),然后可以将其更改为500。而且其中包含的数据可以轻松容纳500个字符。那花了几分钟。

然后我跑了:

ALTER TABLE dbo.ResizeTest ALTER COLUMN [StringField] NVARCHAR(500) NULL;

这只花了11分钟多的时间。

我只是再次重新进行了测试,这次放下了[ResizeTest]表,将两个都NVARCHAR改为VARCHAR,以确保我将苹果与至少看起来像苹果的东西进行了比较;-)。

最初的表创建花费了20秒,而ALTER TABLE花费了2分钟。

因此,就估计停机时间而言,这确实很困难,因为它是基于磁盘I / O速度,是否需要在数据文件和/或事务日志上进行任何自动增长操作的,等等。这可能是为什么我的第一个测试花费11分钟进行更改而第二次测试(即使VARCHARNVARCHAR数据大小的一半)却仅花费2分钟(即文件当时已预先生成)的很大一部分原因。但是,仍然应该记住,我的测试是在不是最快的磁盘的笔记本电脑上运行的,但是它也只是一百万行的2小列(每行22个字节左右)。

既然您问过它将对数据页做什么,这就是您的答案。sp_spaceused在创建表之后,在完成之后ALTER COLUMN和之后,我都做了一个ALTER TABLE dbo.ResizeTest REBUILD;。结果(以下数字基于使用的第二次测试VARCHAR,而不是使用的第一项测试NVARCHAR):

After initial table creation:        526,344 KB
After ALTER COLUMN VARCHAR(500):   1,031,688 KB  <--- !! Yikes!!
After ALTER REBUILD:                 526,472 KB

如果您担心需要使操作保持在最短的时间内,请查看我写的一篇有关这样做的文章:以秒为单位重组1亿行(或更多)表。对不起!(需要免费注册)。


2
因此,我将最差的表复制到了本地实例中(即,磁盘速度较慢,内核数为1/3)。我ALTER连续编辑每一列-每个动作用了不到一秒钟的时间。到完成时,表的大小已增加了一倍,但是一旦我执行了一次操作REBUILD(这也是亚秒级的操作),表就会恢复到其原始大小。
nateirvin

@nateirvin很好听。您可以ALTER TABLE一次完成所有字段,并用逗号分隔每列,从而加快操作速度。如果事务太大,则将表拆分为2个ALTER语句,每个语句占一半。根据表的大小,您甚至可以在两个ALTER语句的每一个之间进行REBUILD。玩的东西。另外,请记住,该操作可能会在一段时间内采用模式锁定,这将阻止对表的所有访问。
所罗门·鲁茨基

1
我分别做每个,ALTER所以我可以跟踪每个之间的大小变化,但是绝对很高兴知道。谢谢!
nateirvin

1

根据我的收集,只要表没有被另一个进程锁定,运行alter语句就不会花很长时间。根据gbn的说法,这只是元数据更改:https : //stackoverflow.com/questions/7261909/is-it-bad-to-use-alter-table-to-resize-a-varchar-column-to-a-larger -尺寸

另外,关于存储方式,SQL Server似乎将varchar数据存储在8k页中,直到它填满整个页面为止,此时将其替换为指针并将其存储为BLOB。

我假设当您更改长度时,您不会截断任何记录。如果是这样,那么最多您要转换为varchar(500)的数据最多应为502个字节长,并且不应具有指针。

因此,长话短说,只要您不截断任何数据,就不会有太大变化。


5
这是绝对不正确的。我不会拒绝投票,因为您实际上已经对其进行了测试(这比某些人所做的要多,因此感谢您这样做),但是您需要进行大规模测试。您链接到的答案是关于增加大小,而不是减少大小。这是两个非常不同的操作。
所罗门·鲁兹基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.