数据库大小 - MDF 太大?

And*_*Bgd 10 sql-server-2005 sql-server shrink

我正在维护一个 SQL Server 2005 数据库,该数据库承载大约 2.9Tb 的数据(2 x 1.45Tb - 我有一个 RAW 架构和一个 ANALYSIS 架构,因此基本上是摄取的数据的两个副本)。恢复模型很简单,.ldf大小为 6Gb。

无论出于何种原因,.mdf都是 7.5Tb。现在,分析表中可能只有 2-3 个额外的列,并且没有多少NVARCHAR(MAX)列,根据我的理解(可能有错误理解 - 如果我错了,请纠正我)可能会导致额外的空间分配。那是在刚刚缩小数据库之后 - 在此之前它约为 9Tb。有什么想法吗?

并且,如果您有其他问题,请告诉我 - 我对数据库管理和优化工作非常陌生(我通常不做这方面的工作:))。

非常感谢!

安德里亚

Dav*_*ett 11

在您的大小估计中,您是否考虑了索引占用的空间量?此外,如果您将文本字段设置为多字节(N[VAR]CHAR而不是[VAR]CHAR),并且输入文件是 UTF-8 或普通的每字符一个字节,那么这会将您的存储要求提高两倍。此外请记住,如果表上有聚集键/索引,则其大小会影响表上的所有其他索引,因为它们包括每一行的聚集键值(因此如果表具有 NCHAR(10 ) INT 将执行的键,即您的聚集键/索引,您不仅在数据页中每行使用了额外的 16 个字节,而且在该表的每个其他索引中每行浪费了 16 个字节)

此外,一些空间将被分配但未使用,要么是因为数据库引擎在删除后留下了一些空间,以便它可以快速再次用于该表中的新数据,要么是因为插入和删除的模式只留下了许多页面的一部分满的。

你可以运行:

SELECT o.name
     , SUM(ps.reserved_page_count)/128.0 AS ReservedMB
     , SUM(ps.used_page_count)/128.0 AS UsedMB
     , SUM(ps.reserved_page_count-ps.used_page_count)/128.0 AS DiffMB
FROM sys.objects o  
JOIN sys.dm_db_partition_stats ps ON o.object_id = ps.object_id  
WHERE OBJECTPROPERTYEX(o.object_id, 'IsMSShipped') = 0  
GROUP BY o.name  
ORDER BY SUM(ps.reserved_page_count) DESC
Run Code Online (Sandbox Code Playgroud)

快速查看哪些表占用了空间。

同样EXEC sp_spaceused在该数据库中运行将返回两个结果集。第一个列出在文件系统中为数据文件分配的总空间以及其中有多少未分配,第二个列出了有多少分配的空间用于数据页、索引页或当前未使用。

sp_spaceused 也将返回给定对象使用的空间,因此您可以循环它以构建一个表进行分析:

-- TEMP TABLES FOR ANALYSIS
CREATE TABLE #tTables (sName NVARCHAR(MAX), iRows BIGINT, iReservedKB BIGINT, iDataKB BIGINT, iIndexKB BIGINT, iUnusedKB BIGINT)
CREATE TABLE #tTmp (sName NVARCHAR(MAX), iRows BIGINT, sReservedKB NVARCHAR(MAX), sDataKB NVARCHAR(MAX), sIndexKB NVARCHAR(MAX), sUnusedKB NVARCHAR(MAX))
-- COLLECT SPACE USE PER TABLE
EXEC sp_msforeachtable 'INSERT #tTmp EXEC sp_spaceused [?];'
-- CONVERT NUMBER-AS-TEXT COLUMNS TO NUMBER TYPES FOR EASIER ANALYSIS
INSERT #tTables SELECT sName, iRows
                     , CAST(REPLACE(sReservedKB, ' KB', '') AS BIGINT)
                     , CAST(REPLACE(sDataKB    , ' KB', '') AS BIGINT)
                     , CAST(REPLACE(sIndexKB   , ' KB', '') AS BIGINT)
                     , CAST(REPLACE(sUnusedKB  , ' KB', '') AS BIGINT) 
                FROM #tTmp
DROP TABLE #tTmp 
-- DO SOME ANALYSIS 
SELECT sName='TOTALS', iRows=SUM(iRows), iReservedKB=SUM(iReservedKB), iDataKB=SUM(iDataKB),  iIndexKB=SUM(iIndexKB), iUnusedKB=SUM(iUnusedKB) FROM #tTables ORDER BY sName
SELECT * FROM #tTables ORDER BY iReservedKB DESC
-- CLEAN UP
DROP TABLE #tTables
Run Code Online (Sandbox Code Playgroud)

上面的代码将输出一个列表中的所有表格大小,以及总计的一行。如果需要,您可以使用各种系统视图(如上面第一个查询中使用的sys.objectssys.dm_db_partition_stats使用的,有关更多详细信息,请参见http://technet.microsoft.com/en-us/library/ms177862.aspx)以获取更多详细信息,例如每个索引使用的空间。


数据文件中有三类未使用的空间:

  1. 没有分配给任何东西的那个(这显示在sp_spaceused没有指定对象的第一个结果集中)
  2. 分配给对象(保留)但当前未使用的对象(这显示在sp_spaceused的输出中的“未使用”计数中。
  3. 锁定在部分使用的页面中(这看起来会被使用,因为所有内容都在单页块中分配,一页长 8,192 字节)。这更难检测/计算。这是由于两个因素的混合:
    • 分页。随着数据的添加,您通常最终会得到部分空白页面(存储引擎总是可以标准化页面内容,但这会非常低效),并且随着行被删除,页面内容不会自动打包(同样可以,但额外的I / O负载通常从值得的)。
    • 存储引擎不会将一行拆分到多个页面上(这与每行 8,192 字节限制来自的页面大小一起)。如果您的行是固定大小并且每行占用 1,100 字节,那么您将“浪费”分配给该表的每个数据块的至少 492 字节(7 行占用 7,700 字节,第 8 行不适合,因此剩余字节将不会)不能使用)。行越宽,情况可能越糟。具有可变长度行的表/索引(比完全固定长度的行更常见)通常更好(但不太容易计算)。
      这里的另一个警告是大对象(TEXT列、[N]VARCHAR(MAX) 值超过特定大小等),因为它们确实被放置在页外,只需在主行数据中占用 8 个字节来保存指向其他地方数据的指针),因此可以打破每行 8,192 字节的限制。

tl;dr:估计预期的数据库大小可能比最初假设的要复杂得多。


Ken*_*her 6

尝试sp_spaceused在您的数据库上运行。例如,它返回:

reserved           data               index_size         unused
------------------ ------------------ ------------------ ------------------
6032 KB            2624 KB            1664 KB            1744 KB
Run Code Online (Sandbox Code Playgroud)

要在数据库上运行它,只需USE在数据库上运行sp_spaceused.

如果它仍然显示大量未使用的空间,您可以再次尝试缩小。有时我确实发现它需要多次尝试。此外,有时我发现缩小单个文件而不是整个数据库效果最好。但是,您可能会发现您有 2.9Tb 的数据和另外 4+Tb 的索引,在这种情况下,7.5TB 是非常合理的。如果您想了解每个表的空间量(数据和索引),那么您也可以sp_spaceused在表级别运行。您可以使用以下命令在数据库中的所有表中运行它:

EXEC sp_msforeachtable 'EXEC sp_spaceused [?];'
Run Code Online (Sandbox Code Playgroud)

尽管公平警告 sp_msforeachtable 没有记录、不受支持并且已知会丢失表。另一方面,我自己也有相当多的运气。

所有这一切都说你的数据库应该有一定比例的可用空间,这取决于你的预期增长。基本上,您要确保您有 6 个月到几年的增长空间。您还需要检查您的autogrowth设置以确保它们适合您的情况。特别是考虑到数据库的大小,您不想使用 % autogrowth