Ini sepertinya tidak terlalu gila, tetapi perhatikan bahwa beberapa dialog UI mungkin tidak memiliki informasi yang benar-benar terkini (inilah sebabnya kami memiliki hal-hal seperti DBCC UPDATEUSAGE ), dan pembulatan juga dapat terlibat dalam beberapa dialog tersebut perhitungan. Akhirnya, dialog menunjukkan ruang total untuk seluruh database , tetapi ruang yang tidak terisi hanya dihitung untuk file data , bukan log.
Mari kita menyatukan beberapa hal.
- Properti basis data dan basis data menyusut menunjukkan hal yang sama (bukan berarti Anda seharusnya berada di UI basis data menyusut!).
- Properti file database menunjukkan 17 + 75 = 92 yang, dengan pembulatan sebelum penambahan, mungkin sama 91,31 dalam 1.
- Untuk ruang yang dialokasikan, menyusut untuk file individual menunjukkan 16,38 + 74,94 = 91,32 - sekali lagi, mungkin beberapa pembulatan di sana, jika tidak tepat sama dengan 1.
- Untuk ruang yang tersedia, menyusut untuk file individual adalah satu-satunya tempat di mana saya mencurigai adanya perbedaan nyata, dan ini karena UI tidak konsisten tentang di mana ia mendapatkan datanya, dan beberapa tempat ini tunduk pada caching yang mengharuskan DBCC UPDATEUSAGE.
Biarkan saya melihat apa yang dijalankan oleh berbagai dialog ini untuk salinan AdventureWorks2012 lokal saya (dengan tabel tertentu diperbesar dari skrip ini ).
EXEC sp_spaceused;
Ini kembali (hanya resultset pertama):
database_size unallocated space
------------- -----------------
1545.81 MB 6.67 MB
Pada dasarnya menjalankan ini, yang - saya sudah konfirmasi melalui jejak - kira-kira permintaan yang sama dieksekusi dari properti database dan dialog menyusut database (saya telah mengukir bagian-bagian yang tidak relevan dari prosedur yang disimpan, dan menambahkan permintaan luar untuk mewakili matematika yang SSMS lakukan untuk tampilan):
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;
Ini mengembalikan kecocokan:
database_size unallocated space
------------- -----------------
1545.8125 6.671875
Semua dialog ini menunjukkan informasi ini dengan benar. Dialog Properti Database:
Kecilkan dialog Database:
Dialog file menyusut , di sisi lain, menjalankan kueri yang sedikit berbeda (sekali lagi ini diukir / disesuaikan untuk kenyamanan):
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;
Perhatikan juga, bahwa selain mendapatkan data ukuran dari fungsi alih-alih DMV, predikat belum diperbarui untuk tipe file baru, seperti filestream / hekaton.
Hasil:
Currently allocated space Available free space
---- ------------------------- --------------------
Data 1517 7.9375 -- wrong
Log 28.8125 25.671875 -- wrong
Masalahnya adalah FILEPROPERTY()
fungsi, yang tidak dijamin mutakhir (bahkan setelah DBCC UPDATEUSAGE(0);
dijalankan; lebih banyak di bawah). Ini berakhir dengan informasi yang menyesatkan ini pada dialog:
Perhatikan, sekali lagi, 6,67 MB itu tidak pernah benar-benar akurat, karena ini hanya mengukur ukuran total basis data - jumlah halaman yang dialokasikan, sepenuhnya mengabaikan log.
Dalam semua kejujuran, jika Anda ingin pelaporan yang akurat tentang ruang yang digunakan dalam database, berhenti menggunakan UI mickey mouse yang menjalankan semua jenis pertanyaan yang berbeda untuk mencari tahu, dan berhenti menggunakan dialog file menyusut untuk mengambil informasi. Ini jelas tunduk pada masalah data basi dalam kasus-kasus tertentu. Jalankan kueri aktual terhadap sumber yang dapat Anda percayai. Inilah yang saya sukai:
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;
Kueri ini mengembalikan tiga angka yang seharusnya terlihat sangat akrab, dan yang tidak:
file_type size available
--------- ----------- ----------
data 1517.000000 6.6718750
log 28.812500 17.9008512
Perhatikan bahwa DBCC SQLPERF juga sedikit rentan terhadap masalah dengan penggunaan ruang, misalnya setelah menjalankan:
DBCC UPDATEUSAGE(0);
Sebaliknya, kueri di atas menghasilkan ini:
file_type size available
--------- ----------- ----------
data 1517.000000 8.0781250
log 28.812500 17.8669481
sp_spaceused
sekarang menghasilkan angka yang cocok juga ( 1545.81 MB / 8.08 MB
), meskipun - lagi - itu hanya ruang yang tersedia dalam file data , dan properti database dan dialog menyusut database juga "akurat" (tetapi dialog menyusut file masih jalan keluar - FILEPROPERTY()
sepertinya tidak terpengaruh UPDATEUSAGE
sama sekali):
Oh, dan mungkin juga menunjukkan apa yang Windows Explorer pikirkan tentang file-file ini, sehingga Anda dapat menghubungkannya dengan perhitungan yang dilakukan untuk menentukan MB:
Seberapa akurat semua ini perlu, tentu saja, tergantung pada apa yang akan Anda lakukan dengan informasi tersebut.