Wolne miejsce w plikach mdf i ldf nie pasuje do wolnego miejsca w bazie danych

9

W SSMS widziałem właściwości związane z rozmiarem pliku i znalazłem poniżej szczegóły dla jednej bazy danych. Tutaj wartości nie pasują do innych właściwości. Tutaj rozmiar mdf, ldf i całkowity rozmiar odpowiada innym wartościom pod każdym oknem. Ale dostępna wolna przestrzeń mdf i ldf, jeśli zostanie dodana, nie jest równa dostępnej wolnej przestrzeni pokazanej w oknie zmniejszania bazy danych i wolnej przestrzeni pokazanej we właściwościach bazy danych. Dotyczy to każdej bazy danych. Dlaczego tak jest Czy ktoś może wyjaśnić logikę tego działania?

W obszarze właściwości bazy danych:

Rozmiar: 91,31 MB
Dostępne miejsce: 13,40 MB

W obszarze plików bazy danych:

Rozmiar mdf: 17 MB
Rozmiar ldf: 75 MB

pod zmniejszoną bazą danych:

Aktualnie przydzielony rozmiar: 91,31 MB
Dostępne wolne miejsce: 13,40 MB

w pliku zmniejszania dla pliku danych:

aktualnie przydzielony rozmiar: 16,38 MB
Dostępne wolne miejsce: 12,63 MB

w pliku zmniejszania dla pliku dziennika:

aktualnie przydzielony rozmiar: 74,94 MB
Dostępne wolne miejsce: 55,62 MB

Badacz IT
źródło

Odpowiedzi:

11

Nie wydaje się to wcale takie szalone, ale zauważ, że niektóre okna dialogowe interfejsu użytkownika mogą nie zawierać całkowicie aktualnych informacji (dlatego mamy takie rzeczy, jak DBCC UPDATEUSAGE ), a zaokrąglanie może być również zaangażowane w niektóre z nich obliczenia. Wreszcie okna dialogowe pokazują całkowitą przestrzeń dla całej bazy danych , ale nieprzydzielone miejsce jest obliczane tylko dla plików danych , a nie dziennika.

Połączmy kilka rzeczy.

  1. Właściwości bazy danych i zmniejszana baza danych pokazują to samo (nie to, że i tak powinieneś być w interfejsie zmniejszanej bazy danych!).
  2. Właściwości pliku bazy danych pokazują 17 + 75 = 92, co przy zaokrągleniu przed dodaniem jest prawdopodobnie tym samym 91,31 w 1.
  3. W przypadku przydzielonego miejsca zmniejszanie dla poszczególnych plików pokazuje 16,38 + 74,94 = 91,32 - ponownie, prawdopodobnie niektóre zaokrąglenia tam, w przeciwnym razie dokładnie pasujące 1.
  4. W przypadku dostępnego miejsca zmniejszanie pojedynczych plików jest jedynym miejscem, w którym podejrzewam prawdziwą rozbieżność, a to dlatego, że interfejs użytkownika jest niespójny co do tego, skąd pobiera dane, a niektóre z tych miejsc podlegają buforowaniu, które wymaga aktualizacji DBCC UPDATEUSAGE.

Zobaczmy, jak działają te różne okna dialogowe dla mojej lokalnej kopii AdventureWorks2012 (z pewnymi tabelami powiększonymi z tego skryptu ).

EXEC sp_spaceused;

Zwraca (tylko pierwszy zestaw wyników):

database_size    unallocated space
-------------    -----------------
   1545.81 MB          6.67 MB

Zasadniczo uruchamia to, co - co potwierdziłem za pomocą śledzenia - jest w przybliżeniu tym samym zapytaniem wykonanym z właściwości bazy danych i okien dialogowych zmniejszania bazy danych (wykreśliłem niepotrzebne części z procedury składowanej i dodałem zapytanie zewnętrzne reprezentujące matematykę które SSMS robi dla wyświetlania):

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;

To zwraca dopasowanie:

database_size    unallocated space
-------------    -----------------
    1545.8125             6.671875

Wszystkie okna dialogowe pokazują te informacje poprawnie. Okno dialogowe Właściwości bazy danych:

Okno dialogowe Właściwości bazy danych

Okno dialogowe Zmniejsz bazę danych:

Okno dialogowe Zmniejsz bazę danych

Z drugiej strony okna dialogowe pliku zmniejszania uruchamiają nieco inne zapytanie (ponownie jest rzeźbione / dostosowane dla wygody):

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;

Zauważ też, że oprócz pobierania danych o wielkości z funkcji zamiast DMV, predykaty nie zostały zaktualizowane dla nowych typów plików, takich jak filestream / hekaton.

Wyniki:

        Currently allocated space    Available free space
----    -------------------------    --------------------
Data                         1517                  7.9375 -- wrong
Log                       28.8125               25.671875 -- wrong

Problemem jest FILEPROPERTY()funkcja, która nie jest gwarantowana na bieżąco (nawet po DBCC UPDATEUSAGE(0);uruchomieniu; więcej poniżej). Kończy się to wprowadzającymi w błąd informacjami w oknach dialogowych:

Nieprawidłowe dostępne odczyty

Zauważ, że 6,67 MB nigdy nie było tak naprawdę dokładne, ponieważ mierzy to tylko całkowity rozmiar bazy danych - liczbę przydzielonych stron, całkowicie ignorując dziennik.

Szczerze mówiąc, jeśli chcesz dokładnego raportowania miejsca używanego w bazie danych, przestań używać interfejsów myszy Myszki Miki, które uruchamiają różnego rodzaju zapytania, aby to zrozumieć, i przestań używać okien dialogowych pliku zmniejszania do pobierania informacji. Są one w oczywisty sposób narażone na problemy z nieaktualnymi danymi w niektórych przypadkach. Uruchom rzeczywiste zapytanie względem źródła, któremu możesz zaufać. Oto, co wolę:

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;

To zapytanie zwraca trzy liczby, które powinny wyglądać bardzo znajomo, i jedną, która nie powinna:

file_type    size           available
---------    -----------    ----------
data         1517.000000     6.6718750
log            28.812500    17.9008512

Zauważ, że DBCC SQLPERF jest również nieco podatny na problemy z wykorzystaniem miejsca, na przykład po uruchomieniu:

DBCC UPDATEUSAGE(0);

Powyższe zapytanie daje to zamiast tego:

file_type    size           available
---------    -----------    ----------
data         1517.000000     8.0781250
log            28.812500    17.8669481

sp_spaceusedteraz daje również pasujące liczby ( 1545.81 MB / 8.08 MB), chociaż - znowu - to tylko przestrzeń dostępna w plikach danych , a okna dialogowe właściwości bazy danych i skurczów bazy danych są również „dokładne” (ale okna dialogowe plików skurczu są nadal daleko - FILEPROPERTY()wydaje się, że wcale nie ma na to wpływu UPDATEUSAGE):

Okno dialogowe Właściwości bazy danych po aktualizacji

Okno dialogowe zmniejszania bazy danych po aktualizacji

Okno dialogowe zmniejszania pliku danych po aktualizacji

Okno dialogowe zmniejszania pliku dziennika po aktualizacji

Aha, i równie dobrze może pokazać, co Eksplorator Windows myśli o tych plikach, więc możesz odnieść się do obliczeń wykonanych w celu ustalenia MB:

Rozmiary plików w systemie Windows

To, jak dokładne musi być to wszystko, zależy oczywiście od tego, co zrobisz z informacjami.

Aaron Bertrand
źródło