减少数据库的大小

Bre*_*ett 5 performance sql-server-2008 sql-server shrink disk-space

SQL Server 新手在这里。我是一个 MySQL 人。我正在为他们的 2008 SQL Server 中的客户查看一些东西,需要一些建议。设计数据库的人选择记录疯狂数量的东西并且从不刷新这些日志表。

最大的餐桌商店完成 XML来自应用程序和 eBay 等网站的 API 之间交易的文档。我只能假设大约 230 GB 的数据库会影响性能。我猜这些表不会在应用程序中查询,但即便如此,我也不喜欢如此庞大的数据库的想法。清除日志表后,我预计总剩余大小约为 30GB。

我想就如何解决这个问题提供一些建议。从我对这个主题的了解来看,删除一堆数据后,数据库文件不会自动缩小大小。我还读到缩小和重新索引是不好的。

  • 这个大型数据库是否会损害其他表的性能?
  • 我应该做些什么吗?
  • 我怎样才能安全地做一些事情来提高性能?

Aar*_*and 10

如果您打算继续在此数据库中记录数据,那么您最不想做的就是缩小数据库文件(然后执行索引维护,这将需要它再次增长)。不要介意这些收缩和增长操作会影响性能,最终结果不会比开始时更好。

由于文件只会再次增长,这是一个非常徒劳的操作 - 就像还在淋浴时擦干。您将如何处理临时释放的所有磁盘空间?将它租给另一个应用程序,直到数据库需要再次增长?当然不是。如果数据库一次增长到那个大小,它会再次增长到那个大小,但是重用文件中的空间会更有效率,而没有所有这些不必要的文件本身的收缩-增长-收缩-增长过山车.

即使您将日志记录表移动到另一个数据库,您也应该尽您所能将数据文件预先分配到可以容纳您想要保存的日志记录量的大小(一周、一个月,您有什么? )。通过每天清除数据来保持此数据库修剪,并且不再担心收缩和重新索引。如果大小合适,应该总是有一些可用空间,但不能有过多的可用空间。如果你需要重新索引(你真的不应该,如果你的聚集索引是日期时间或其他单调的),在清除后(当你有最多的可用空间时)这样做,而不是在收缩后(当你有最少的时候)。

您可以执行 Mark 建议的操作,而无需向应用程序引入新数据库,也无需更改应用程序或其与数据库的接口(当然,一个重要的更改是删除任何外键或其他依赖于数据库的功能) . 您可以简单地在新数据库中创建您的表,然后向当前数据库中的表添加一个INSTEAD OF INSERT 触发器(我假设日志表没有更新,但您可能还需要一个 INSTEAD OF DELETE 触发器如果您不直接控制执行清除的过程)。这将有助于写入,但您必须将读取指向其他地方,因为没有 INSTEAD OF SELECT 触发器。另一种选择是重命名现有表并创建同义词 甚至是指向新表的视图。


如果您需要清理已增长的日志表,我会避免使用单个原子事务,例如:

DELETE dbo.logs_table WHERE [datetime] < '20121201';
Run Code Online (Sandbox Code Playgroud)

这将导致大量日志增长,并且需要很长时间。相反,您可以将清理分成块,例如

BEGIN TRANSACTION;

SELECT 1;

WHILE @@ROWCOUNT > 0
BEGIN
  COMMIT TRANSACTION;

  -- if in simple: CHECKPOINT
  -- otherwise: BACKUP LOG

  BEGIN TRANSACTION;

  DELETE TOP (1000) FROM dbo.logs_table WHERE [datetime] < '20121201';
END
Run Code Online (Sandbox Code Playgroud)

我随意选择了 1000 和 12 月 1 日,我不知道哪个最适合您的情况。关键是您希望保持事务简短和包含,并在清理表时防止任何长期影响。我过去使用过的另一种选择,不是删除表中 99% 的垃圾,而是将要保留的 1% 移到新表并删除旧表。

BEGIN TRANSACTION;

SELECT * 
  INTO dbo.new_logs_table 
  FROM dbo.logs_table
  WHERE [datetime] >= '20121201'

COMMIT TRANSACTION;

-- create indexes/constraints/triggers on dbo.new_logs_table

BEGIN TRANSACTION;
  DROP TABLE dbo.logs_table;
  EXEC sp_rename N'dbo.new_logs_table', N'logs_table', N'OBJECT';
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)

如果您说日志从未被清除过,那么您很可能处于这样一种情况:数据库的大小将超出您的预期(例如,如果您只打算保留一个星期)一次的日志)。在这种情况下,我可能会进行收缩操作,但前提是确实有必要(例如,您确实需要将空间用于其他目的)。一堆空页面不会影响您的备份或其他操作,这些页面最终将被完全释放和重用。


Mar*_*ith 9

最大的表存储来自应用程序和 eBay 等网站的 API 之间交易的完整 XML 文档。

我目前正在使用一个完全相同的系统。虽然 Mat 关于 230GB 以今天的标准来看并不大的评论是公平的,但它仍然比系统运行所需的多 200GB。它可能会占用缓冲池,它肯定会导致更大和更长的备份,而且最重要的是,它在发生灾难时需要更长的恢复时间。

更可取的做法(如果应用程序代码可访问并且处于可以容忍更改的合适状态)是将任何非关键日志记录推送到不同的数据库。然后,您可以将其切换到 SIMPLE 恢复并放弃事务日志备份。显然,这仅适用于认为可以接受时间点恢复丢失的数据。

在我查看的情况下,正在记录的 API 请求/响应文档实际上是重复数据。交易详细信息存储在其他地方的数据库中,文档仅用于调试目的。

或者,更频繁地清除数据。

但是...如果您的评估是正确的并且感兴趣的数据是 30GB,那么 32GB 的服务器专用于此数据库,那应该足够了。我倾向于建议您对问题的根源进行更深入的分析,而不是直接尝试过早地解决日志记录/大小问题。

破解 DMV 查询。Glen Berry 的 DMV 诊断脚本包含用于识别消耗最多 IO 或 CPU 时间的过程和即席查询的示例。sp_whoisactive对于实时分析非常有用。

如果您发现任何感兴趣的内容,请随时发布包含详细信息的新问题。