Czy można defragmentować tabele systemowe SQL Server?

15

Mamy kilka baz danych, w których tworzonych i upuszczanych jest wiele tabel. Z tego, co możemy powiedzieć, SQL Server nie przeprowadza wewnętrznej konserwacji tabel systemowych , co oznacza, że ​​z czasem mogą się bardzo rozdrobnić i rozdęć. Powoduje to niepotrzebną presję na pulę buforów, a także negatywnie wpływa na wydajność operacji, takich jak obliczanie wielkości wszystkich tabel w bazie danych.

Czy ktoś ma sugestie dotyczące minimalizacji fragmentacji tych podstawowych tabel wewnętrznych? Jednym oczywistym rozwiązaniem mogłoby być uniknięcie tworzenia tylu tabel (lub tworzenia wszystkich tabel przejściowych w tempdb), ale na potrzeby tego pytania powiedzmy, że aplikacja nie ma takiej elastyczności.

Edycja: Dalsze badania pokazują to pytanie bez odpowiedzi , które wydaje się ściśle powiązane i wskazuje, że pewna forma ręcznej konserwacji ALTER INDEX...REORGANIZEmoże być opcją.


Wstępne badania

Metadane dotyczące tych tabel można wyświetlić w sys.dm_db_partition_stats:

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136

Jednak sys.dm_db_index_physical_statswydaje się , że nie obsługuje przeglądania fragmentacji tych tabel:

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM sys.dm_db_index_physical_stats(
    DB_ID(),
    OBJECT_ID('sys.syscolpars'),
    NULL,
    NULL,
    'DETAILED'
)

Skrypty Oli Hallengren zawierają również parametr umożliwiający rozważenie defragmentacji is_ms_shipped = 1obiektów, ale procedura po cichu ignoruje tabele podstawowe systemu, nawet jeśli ten parametr jest włączony. Ola wyjaśniła, że ​​jest to oczekiwane zachowanie; msdb.dbo.backupsetbrane są pod uwagę tylko tabele użytkowników (nie tabele systemowe), które są ms_shipped (np. ).

-- Returns code 0 (successful), but does not do any work for system base tables.
-- Instead of the expected commands to update statistics and reorganize indexes,
-- no commands are generated. The script seems to assume the target tables will
-- appear in sys.tables, but this does not appear to be a valid assumption for
-- system tables like sys.sysrowsets or sys.syscolpars.
DECLARE @result int;
EXEC @result = IndexOptimize @Databases = 'Test',
        @FragmentationLow = 'INDEX_REORGANIZE',
        @FragmentationMedium = 'INDEX_REORGANIZE',
        @FragmentationHigh = 'INDEX_REORGANIZE',
        @PageCountLevel = 0,
        @UpdateStatistics = 'ALL',
        @Indexes = '%Test.sys.sysrowsets.%',
        -- Proc works properly if targeting a non-system table instead
        --@Indexes = '%Test.dbo.Numbers.%',
        @MSShippedObjects = 'Y',
        @Execute = 'N';
PRINT(@result);


Dodatkowe wymagane informacje

Użyłem adaptacji zapytania Aarona poniżej wykorzystania puli buforów tabel systemowych i okazało się, że w puli buforów znajdują się dziesiątki GB tabel systemowych tylko dla jednej bazy danych, w niektórych przypadkach około 80% tego miejsca to wolne miejsce .

-- Compute buffer pool usage by system table
SELECT OBJECT_NAME(p.object_id),
    COUNT(b.page_id) pages,
    SUM(b.free_space_in_bytes/8192.0) free_pages
FROM sys.dm_os_buffer_descriptors b
JOIN sys.allocation_units a
    ON a.allocation_unit_id = b.allocation_unit_id
JOIN sys.partitions p
    ON p.partition_id = a.container_id
    AND p.object_id < 1000 -- A loose proxy for system tables
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY pages DESC

wprowadź opis zdjęcia tutaj

Geoff Patterson
źródło

Odpowiedzi:

11

Czy na pewno zidentyfikowałeś tę tabelę systemową jako jedyne źródło „niepotrzebnego nacisku na pulę buforów, a także negatywnie wpływa na wydajność operacji, takich jak obliczanie wielkości wszystkich tabel w bazie danych”? Czy jesteś pewien, że ta tabela systemowa nie jest samozarządzana w taki sposób, że (a) fragmentacja jest zminimalizowana lub utrzymywana w tajemnicy lub po prostu (b) skutecznie zarządzana w pamięci, aby poziomy defragmentacji naprawdę nie miały większego wpływu?

Możesz zobaczyć, ile stron jest w użyciu, i zobaczyć, ile wolnego miejsca jest na stronach, które są w pamięci ( page_free_space_percentzawsze NULLw przydziałach DMF, ale jest to dostępne z bufora DMV) - to powinno dać ci pewien pomysł jeśli to, o co się martwisz, jest czymś, czym powinieneś się martwić:

SELECT 
  Number_of_Pages = COUNT(*), 
  Number_of_Pages_In_Memory = COUNT(b.page_id),
  Avg_Free_Space = AVG(b.free_space_in_bytes/8192.0) 
FROM sys.dm_db_database_page_allocations
(
  DB_ID(),
  OBJECT_ID(N'sys.syscolpars'),
  NULL,NULL,'DETAILED'
) AS p
LEFT OUTER JOIN sys.dm_os_buffer_descriptors AS b
ON b.database_id = DB_ID() 
AND b.page_id = p.allocated_page_page_id 
AND b.file_id = p.allocated_page_file_id;

Jeśli twoja liczba stron jest niewielka (np. Prawdopodobnie <10000 dla tabel systemowych) lub jeśli ilość wolnego miejsca jest „niska” (nie jestem pewien, jakie są typowe progi dla przebudowy / przebudowy), skup się na innych, bardziej interesujących, nisko wiszących owocach .

Jeśli twoja liczba stron jest duża, a ilość wolnego miejsca jest „wysoka”, ok, to może daję SQL Serverowi zbyt dużo uznania za jego samodzielną konserwację. Jak pokazałeś z drugiego pytania , to działa ...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

... i robi zmniejszenie fragmentacji. Chociaż może to wymagać podwyższonych uprawnień (nie próbowałem jako peon).

Być może możesz to robić okresowo w ramach własnej konserwacji, jeśli poprawi to samopoczucie i / lub będziesz miał jakiekolwiek dowody, że ma to jakikolwiek pozytywny wpływ na twój system.

Aaron Bertrand
źródło
Dodałem kolejną odpowiedź podsumowującą to, co skończyliśmy, a następnie wyczyściłem poprzednie komentarze tutaj. Jeszcze raz dziękuję za pomoc!
Geoff Patterson
7

W oparciu o wskazówki z odpowiedzi Aarona oraz dodatkowe badania, oto krótki opis przyjętego przeze mnie podejścia.

Z tego, co mogę powiedzieć, opcje kontroli fragmentacji systemowych tabel podstawowych są ograniczone. Poszedłem dalej i zgłosiłem problem z Connect, aby zapewnić lepszą widoczność, ale w międzyczasie wydaje się, że opcje obejmują takie rzeczy jak sprawdzenie puli buforów lub sprawdzenie średniej liczby bajtów na wiersz.

Następnie stworzyłem procedurę wykonywania `ALTER INDEX ... REORGANIZE na wszystkich tabelach podstawowych systemu . Wykonanie tej procedury na kilku z naszych (najczęściej używanych) serwerów deweloperskich pokazało, że skumulowany rozmiar systemowych tabel bazowych został przycięty nawet o 50 GB (przy ~ 5 MM tabel użytkowników w systemie, więc jest to skrajny przypadek).

Jedno z naszych nocnych zadań konserwacyjnych, które pomaga wyczyścić wiele tabel użytkowników utworzonych przez różne testy jednostkowe i rozwój, poprzednio zajmowało ~ 50 minut. Połączenie sp_whoisactive, sys.dm_os_waiting_tasksi DBCC PAGEwykazano, że czeka zostały zdominowane przez I / O tabel bazy danych systemu.

Po reorganizacji wszystkich tabel podstawowych systemu zadanie konserwacji spadło do ~ 15 minut. Nadal były pewne oczekiwania na operacje we / wy, ale zostały one znacznie zmniejszone, być może z powodu większej ilości danych pozostających w pamięci podręcznej i / lub większej liczby problemów z powodu mniejszej fragmentacji.

Dlatego doszedłem do wniosku, że dodanie ALTER INDEX...REORGANIZEsystemowych tabel podstawowych do planu konserwacji może być użyteczną rzeczą do rozważenia, ale prawdopodobnie tylko w przypadku scenariusza, w którym w bazie danych tworzona jest niezwykła liczba obiektów.

Geoff Patterson
źródło
+1 zarówno za twoje pytanie, jak i odpowiedź - elementy wewnętrzne są trochę czarną skrzynką, a pomogłeś rzucić nieco światła na coś, co wygląda na naprawdę paskudny scenariusz wydajności (nawet jeśli twoje jest przypadkowe).
Max Vernon,