Điều này có vẻ không thực sự điên rồ, nhưng lưu ý rằng một số hộp thoại UI có thể không có thông tin cập nhật hoàn toàn (đây là lý do tại sao chúng ta có những thứ như DBCC UPDATEUSAGE ), và làm tròn cũng có thể liên quan đến một số trong số đó. tính toán. Cuối cùng, các hộp thoại hiển thị cho bạn tổng dung lượng cho toàn bộ cơ sở dữ liệu , nhưng không gian chưa phân bổ chỉ được tính cho các tệp dữ liệu , không phải nhật ký.
Hãy kết hợp một số thứ.
- Thuộc tính cơ sở dữ liệu và cơ sở dữ liệu thu nhỏ cho thấy điều tương tự (không phải là bạn nên có trong giao diện người dùng cơ sở dữ liệu thu nhỏ nào!).
- Thuộc tính tệp cơ sở dữ liệu hiển thị 17 + 75 = 92, với làm tròn trước khi thêm, có thể giống với 91,31 trong 1.
- Đối với không gian được phân bổ, thu nhỏ cho các tệp riêng lẻ hiển thị 16,38 + 74,94 = 91,32 - một lần nữa, có thể là một số làm tròn ở đó, nếu không thì khớp chính xác 1.
- Đối với không gian có sẵn, thu nhỏ cho các tệp riêng lẻ là nơi duy nhất tôi nghi ngờ có sự khác biệt thực sự và điều này là do UI không nhất quán về nơi lấy dữ liệu của nó và một số vị trí này phải tuân theo bộ đệm ẩn yêu cầu DBCC UPDATEUSAGE.
Hãy để tôi xem những hộp thoại khác nhau này chạy cho bản sao AdventureWorks2012 cục bộ của tôi (với các bảng nhất định được phóng to từ tập lệnh này ).
EXEC sp_spaceused;
Trả về này (chỉ kết quả đầu tiên):
database_size unallocated space
------------- -----------------
1545.81 MB 6.67 MB
Về cơ bản chạy cái này, mà - tôi đã xác nhận qua dấu vết - gần như là cùng một truy vấn được thực hiện từ các thuộc tính cơ sở dữ liệu và hộp thoại thu nhỏ cơ sở dữ liệu (Tôi đã khắc các phần không liên quan từ thủ tục được lưu trữ và thêm một truy vấn bên ngoài để biểu diễn toán học SSMS hiện để hiển thị):
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;
Điều này trả về một trận đấu:
database_size unallocated space
------------- -----------------
1545.8125 6.671875
Tất cả các hộp thoại hiển thị thông tin này một cách chính xác. Hộp thoại Thuộc tính cơ sở dữ liệu:
Hộp thoại Shrink Database:
Mặt khác , các hộp thoại thu nhỏ tệp chạy một truy vấn hơi khác (một lần nữa, đây được khắc / điều chỉnh cho thuận tiện):
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;
Cũng lưu ý rằng, ngoài việc lấy dữ liệu kích thước từ một chức năng thay vì DMV, các vị từ chưa được cập nhật cho các loại tệp mới, như filestream / hekaton.
Các kết quả:
Currently allocated space Available free space
---- ------------------------- --------------------
Data 1517 7.9375 -- wrong
Log 28.8125 25.671875 -- wrong
Vấn đề là FILEPROPERTY()
chức năng, không được đảm bảo cập nhật (ngay cả sau khi DBCC UPDATEUSAGE(0);
được chạy; bên dưới nhiều hơn). Điều này kết thúc với thông tin sai lệch này trên các hộp thoại:
Lưu ý, một lần nữa, 6,67 MB đó không bao giờ thực sự chính xác, vì điều này chỉ đo tổng kích thước cơ sở dữ liệu - số lượng trang được phân bổ, hoàn toàn không quan tâm đến nhật ký.
Thành thật mà nói, nếu bạn muốn báo cáo chính xác dung lượng được sử dụng trong cơ sở dữ liệu, hãy ngừng sử dụng UI chuột mickey chạy tất cả các loại truy vấn khác nhau để tìm ra điều này và ngừng sử dụng hộp thoại thu nhỏ tệp để truy xuất thông tin. Đây rõ ràng là đối tượng của vấn đề dữ liệu cũ trong một số trường hợp nhất định. Chạy một truy vấn thực tế đối với một nguồn mà bạn có thể tin tưởng. Đây là những gì tôi thích:
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;
Truy vấn này trả về ba số trông rất quen thuộc và một số không nên:
file_type size available
--------- ----------- ----------
data 1517.000000 6.6718750
log 28.812500 17.9008512
Lưu ý rằng DBCC SQLPERF cũng hơi có vấn đề với việc sử dụng không gian, ví dụ như sau khi chạy:
DBCC UPDATEUSAGE(0);
Các truy vấn trên mang lại điều này thay vì:
file_type size available
--------- ----------- ----------
data 1517.000000 8.0781250
log 28.812500 17.8669481
sp_spaceused
bây giờ cũng mang lại các số trùng khớp ( 1545.81 MB / 8.08 MB
), mặc dù - một lần nữa - đó chỉ là không gian có sẵn trong tệp dữ liệu và các hộp thoại thu nhỏ thuộc tính cơ sở dữ liệu và cơ sở dữ liệu cũng "chính xác" (nhưng hộp thoại tệp thu nhỏ vẫn còn lối thoát - FILEPROPERTY()
dường như không bị ảnh hưởng bởi UPDATEUSAGE
tất cả):
Ồ, và cũng có thể hiển thị những gì Windows Explorer nghĩ về các tệp này, vì vậy bạn có thể liên quan đến các tính toán được thực hiện để xác định MB:
Tất nhiên điều này chính xác đến mức nào, tất nhiên, phụ thuộc vào những gì bạn sẽ làm với thông tin.