这似乎并没有那么疯狂,但是请注意,某些UI对话框可能没有完全最新的信息(这就是为什么我们有DBCC UPDATEUSAGE之类的原因),其中一些还涉及了舍入计算。最后,对话框显示整个数据库的总空间,但未分配空间仅针对数据文件而非日志计算。
让我们合并一些东西。
- 数据库属性和收缩数据库显示相同的内容(不是您无论如何都应该处于收缩数据库UI中!)。
- 数据库文件属性显示17 + 75 = 92,加法前四舍五入可能与1中的91.31相同。
- 对于分配的空间,单个文件的缩小显示16.38 + 74.94 = 91.32-再次,可能是四舍五入,否则精确匹配1。
- 对于可用空间,我怀疑真正的差异是唯一减少单个文件的地方,这是因为UI关于其数据获取位置不一致,并且其中一些地方需要进行缓存,因此需要DBCC UPDATEUSAGE。
让我看看为我的AdventureWorks2012本地副本运行这些不同的对话框的内容(某些表已从该脚本放大)。
EXEC sp_spaceused;
返回(仅第一个结果集):
database_size unallocated space
------------- -----------------
1545.81 MB 6.67 MB
从本质上讲,运行此命令(我已通过跟踪确认)与从数据库属性和数据库收缩对话框执行的查询大致相同(我从存储过程中剔除了不相关的部分,并添加了一个外部查询来表示数学运算该SSMS进行显示):
SELECT database_size = DbSize*8.0/1024 + LogSize*8.0/1024,
[unallocated space] = (DbSize-SpaceUsed)*8.0/1024
FROM
(
SELECT
(SELECT SUM(CAST(df.size as float)) FROM sys.database_files AS df
WHERE df.type in ( 0, 2, 4 ) ) AS [DbSize],
SUM(a.total_pages) AS [SpaceUsed],
(SELECT SUM(CAST(df.size as float)) FROM sys.database_files AS df
WHERE df.type in (1, 3)) AS [LogSize]
FROM sys.partitions p
join sys.allocation_units a on p.partition_id = a.container_id
left join sys.internal_tables it on p.object_id = it.object_id
) AS x;
这将返回一个匹配项:
database_size unallocated space
------------- -----------------
1545.8125 6.671875
这些对话框均正确显示此信息。数据库属性对话框:
收缩数据库对话框:
另一方面,收缩文件对话框运行的查询略有不同(为了方便起见,再次对其进行了雕刻/调整):
SELECT SUBSTRING(name, CHARINDEX('_',name)+1, 4),
[Currently allocated space] = size/1024.0,
[Available free space] = (Size-UsedSpace)/1024.0
FROM
(
SELECT s.name,
CAST(FILEPROPERTY(s.name, 'SpaceUsed') AS float)*CONVERT(float,8) AS [UsedSpace],
s.size * CONVERT(float,8) AS [Size]
FROM sys.database_files AS s
WHERE (s.type IN (0,1))
) AS x;
还要注意,除了从函数而不是DMV中获取大小数据外,还没有为新文件类型(例如文件流/ hekaton)更新谓词。
结果:
Currently allocated space Available free space
---- ------------------------- --------------------
Data 1517 7.9375 -- wrong
Log 28.8125 25.671875 -- wrong
问题出在FILEPROPERTY()
函数上,不能保证它是最新的(即使在DBCC UPDATEUSAGE(0);
运行后;下面还有更多)。最终,这些错误信息出现在对话框中:
再次注意,6.67 MB从未真正准确,因为这仅是在测量数据库的总大小-已分配的页数,而完全忽略了日志。
老实说,如果您想准确报告数据库中使用的空间,请停止使用运行各种查询的米奇鼠标UI来解决此问题,并停止使用收缩文件对话框来获取信息。在某些情况下,这些数据显然会过时。对您可以信任的源运行实际查询。这是我更喜欢的:
DECLARE @log_used DECIMAL(19,7);
CREATE TABLE #x(n SYSNAME, s DECIMAL(19,7), u DECIMAL(19,7), b BIT);
INSERT #x EXEC('DBCC SQLPERF(LogSpace);');
SELECT @log_used = u FROM #x WHERE n = DB_NAME();
DROP TABLE #x;
DECLARE @data_used DECIMAL(19,7);
SELECT @data_used = SUM(a.total_pages)*8/1024.0
FROM sys.partitions AS p
INNER JOIN sys.allocation_units AS a
ON p.[partition_id] = a.container_id;
;WITH x(t,s) AS
(
SELECT [type] = CASE
WHEN [type] IN (0,2,4) THEN 'data' ELSE 'log' END,
size*8/1024.0 FROM sys.database_files AS f
)
SELECT
file_type = t,
size = s,
available = s-CASE t WHEN 'data' THEN @data_used ELSE @log_used END
FROM x;
此查询返回三个看起来很熟悉的数字,一个不应返回:
file_type size available
--------- ----------- ----------
data 1517.000000 6.6718750
log 28.812500 17.9008512
请注意,例如,在运行后,DBCC SQLPERF也容易出现空间使用问题:
DBCC UPDATEUSAGE(0);
上面的查询产生了这个:
file_type size available
--------- ----------- ----------
data 1517.000000 8.0781250
log 28.812500 17.8669481
sp_spaceused
现在也产生匹配的数字(1545.81 MB / 8.08 MB
),即使-再次-只是数据文件中的可用空间,并且数据库属性和数据库收缩对话框也“准确”(但是收缩文件对话框仍然方式- FILEPROPERTY()
似乎根本不受任何影响UPDATEUSAGE
):
哦,不妨显示Windows资源管理器对这些文件的看法,因此您可以将其与确定MB的计算相关联:
当然,所有这些需要达到的精确度取决于您将如何处理这些信息。