我们有一个 SQL Server 2012 Enterprise 实时事务数据库,现在每月增长超过 1G,并且正在成为我们的一个大小问题。目前为23G。字符类型字段都是 Unicode,我计算出仅将 2 个这样的字段平均每个 206 个字符转换为非 Unicode 节省了 5G 空间,如果我们将其中的一些从 nchar 和 nvarchar 转换为 char 和varchar 类型。这些字段永远不需要保存不能出现在 SQL_Latin1_General_CP1_CI_AS 排序规则中的 Unicode 字符,因为它们最初以纯 ASCII 形式出现,并且始终按照协议标准这样做。
我是软件架构师和首席 C# 开发人员,尽管只是 DBA 黑客,否则我不会将我们的数据库设计为具有 Unicode 字段用于大量表,而这些表在 3 年前创建数据库时不需要这些字段的 Unicode。在我们最终转换到 AlwaysOn 环境以帮助解决各种性能和备份问题之前,我现在想纠正这个错误。
在缩减这两个或更多字段后,我们希望将数据库缩小一次,以利用节省的空间进行完整备份,并为 AlwaysOn 环境播种。
问题是——
将列从 nchar/nvarchar 类型缩减为 char/varchar 类型的最安全、最有效的转换技术是什么?特别是 当同一个表中有多个字段需要转换时。我测试了为我想从 nvarchar(max) 转换为 varchar(max) 的两个主要字段执行“添加新列、设置 new=old、删除旧的、将旧的重命名为新的”,这花了 81 分钟我们的测试服务器(4 个虚拟核心,8G 内存)在磁盘空间用完之前即使磁盘上还剩下 8G,并且数据库设置了无限大小(无法为对象'dbo.abc'分配空间。'PK_xyz'在数据库 'xxx' 中,因为 'PRIMARY' 文件组已满)。在收到磁盘警告后,我确实在完成之前删除了一个旧数据库,所以它可能没有计算那个新空间。不管它太慢了。这只是这些列中最大的两个(1260 万行),并且只占用 2% 到 3% 的 CPU 忙,因此看起来效率不高,并且如果我们要转换这两个字段甚至更不用说任何其他字段,则表示不可接受的停机时间。这两个字段的平均字段大小仅为 206 个字符或 412 个字节。我打算尝试的另一种技术是在新模式中创建新表 def,从旧表中选择它,然后在模式之间移动表并删除旧表。我在桌面上有一个 FK 和索引要处理。我打算尝试的另一种技术是在新模式中创建新表 def,从旧表中选择它,然后在模式之间移动表并删除旧表。我在桌面上有一个 FK 和索引要处理。我打算尝试的另一种技术是在新模式中创建新表 def,从旧表中选择它,然后在模式之间移动表并删除旧表。我在桌面上有一个 FK 和索引要处理。
如果我弄清楚如何在可接受的维护窗口内有效地执行#1,那么进行一次性收缩并最终得到有组织/重建的索引和更新的统计信息的最安全做法是什么?我理解不进行常规收缩的逻辑,有时它实际上可以增加尺寸。
是否有任何第三方工具可以进行备份并将其恢复到具有修改后的字段定义或以其他方式转换某些字段类型的新数据库中?
欢迎提出任何建议和最佳实践。
谢谢,戴夫
关于:
和
一般来说,使用理想模式制作表的副本是我的首选方法。但是,如果您现在可能只有足够的空间来转换两列,您确定您有足够的空间来制作整个表格的副本吗?
此外,新表只需要有一个不同的名称。它不需要在不同的模式中。
由于您使用的是企业版,您是否考虑过甚至考虑过启用数据压缩?它不仅会产生您在
NCHAR
/NVARCHAR
字段上寻找的效果,而且还会在其他类型的其他字段上节省空间。有两种类型的压缩:行和页。您应该仔细阅读它们并运行存储过程来估计您的节省金额。
启用压缩可以作为一项
ONLINE
操作来完成,但可能需要一些磁盘空间。如果您没有可用空间,那么您可以考虑一种混合方法,您可以将表的副本构建为TableNEW
,并且已经创建了聚簇索引,并在启用压缩的情况下创建。然后你应该可以慢慢填充TableNEW
,数据会在输入时压缩。当然,你会想使用 INSERT INTO...SELECT 来批量完成。直到您删除原始表并对TableNEW
.请记住,在某些情况下,您可能不会节省那么多空间,或者节省空间不值得增加 CPU 活动。但是,这一切都取决于很多因素,所以它确实应该在您的系统上进行测试。
你总是可以采取以下方法:
但同样,就像我们所做的任何事情一样,它应该经过测试。多年来,我一直听说 CPU 上的“XML 解析”有多糟糕,压缩应该有多糟糕,但实际上,这些担忧常常被夸大了。唯一知道的方法是在您的系统上进行测试。(ps,以防万一不清楚是纯文本媒体,这些最后的陈述并不是在攻击@Kin 在他的回答中所说的需要对 CPU 活动增加保持谨慎。他是正确的,至少在某种程度上是正确的。我只是提醒大家一定要从当前的硬件和软件以及系统设置的角度来考虑。)
您可以使用架构开关或添加可为空的 varchar(具有适当长度)列和批处理(例如 1K 或 10K)更新行,更新完成后,删除旧列并重命名新列。最后,重建索引。
另一种方法是创建一个具有所需正确数据类型的单独数据库,bcp 输出数据并将数据批量插入新数据库,然后重建索引并将其重命名为旧名称(删除旧数据库)。
本机格式的 BCP 和批量插入非常快,因为您将在同一台服务器上进行。此过程假定您有足够的磁盘空间。 我在不到 20 分钟的时间内完成了一个 400GB 的数据库 bcp out 和批量插入。像往常一样,彻底测试您的整个过程,并且您必须在维护窗口期间执行此操作。
如果您确定您的数据库永远不会再增长到那个大小,那么缩小它就会给您那个空间。确保你有一个合理的自动增长设置(并保持自动增长以 MB 为单位而不是以百分比为单位)并预先调整你的数据和日志文件(这样它们就不必经常自动增长)。还启用即时文件初始化,以便数据文件可以利用它的强大功能。
从来没听说过。我会说这是不可能的,除非你暗示 - 与你当前的数据库和未来的数据库(具有正确数据类型的数据库)进行模式比较并生成脚本进行同步。为此,Redgate 的模式比较是一个极好的工具。我用过它,它是救命稻草!
我同意上面关于使用数据压缩的答案- 行或页,但它伴随着CPU 的费用。