As tabelas de sistema do SQL Server podem ser desfragmentadas?


15

Temos vários bancos de dados nos quais um grande número de tabelas é criado e descartado. Pelo que sabemos, o SQL Server não realiza nenhuma manutenção interna nas tabelas base do sistema , o que significa que elas podem se tornar muito fragmentadas ao longo do tempo e inchadas em tamanho. Isso coloca pressão desnecessária no buffer pool e também afeta negativamente o desempenho das operações, como calcular o tamanho de todas as tabelas em um banco de dados.

Alguém tem sugestões para minimizar a fragmentação nessas tabelas internas principais? Uma solução óbvia poderia evitar criar tantas tabelas (ou criar todas as tabelas transitórias no tempdb), mas, para o propósito desta pergunta, digamos que o aplicativo não tenha essa flexibilidade.

Edit: Mais pesquisas mostram essa pergunta sem resposta , que parece intimamente relacionada e indica que alguma forma de manutenção manual via ALTER INDEX...REORGANIZEpode ser uma opção.


Pesquisa inicial

Os metadados sobre essas tabelas podem ser visualizados em 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

No entanto, sys.dm_db_index_physical_statsnão parece suportar a exibição da fragmentação dessas tabelas:

-- 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'
)

Os scripts de Ola Hallengren também contêm um parâmetro para considerar a desfragmentação de is_ms_shipped = 1objetos, mas o procedimento ignora silenciosamente as tabelas base do sistema, mesmo com esse parâmetro ativado. Ola esclareceu que esse é o comportamento esperado; somente tabelas de usuário (não tabelas de sistema) que são ms_shipped (por exemplo msdb.dbo.backupset) são consideradas.

-- 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);


Informações adicionais solicitadas

Usei uma adaptação da consulta de Aaron abaixo do uso do pool de buffers da tabela do sistema, e isso constatou que existem dezenas de GB de tabelas do sistema no buffer pool para apenas um banco de dados, com ~ 80% desse espaço sendo espaço livre em alguns casos .

-- 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

insira a descrição da imagem aqui

Respostas:


11

Você tem certeza de que identificou positiva e precisamente essa tabela do sistema como a única fonte de "pressão desnecessária no buffer pool e também afeta negativamente o desempenho das operações, como calcular o tamanho de todas as tabelas em um banco de dados"? Você tem certeza de que essa tabela do sistema não é autogerenciada de tal forma que (a) a fragmentação é minimizada ou controlada secretamente ou apenas (b) gerenciada com eficiência na memória, para que os níveis de desfragmentação realmente não afetem nada?

Você pode ver quantas páginas estão em uso e quanto espaço livre há nas páginas que estão na memória ( page_free_space_percentestá sempre NULLno DMF de alocações, mas está disponível no DMV do buffer) - isso deve lhe dar uma idéia se o que você está preocupando é realmente algo com o qual você deve se preocupar:

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;

Se seu número de páginas for pequeno (como provavelmente <10000 para tabelas do sistema) ou se o espaço livre for "baixo" (não sei quais são seus limites típicos para reorganizar / reconstruir), concentre-se em outras frutas mais interessantes .

Se o seu número de páginas for grande e o espaço livre for "alto", ok, talvez eu esteja dando muito crédito ao SQL Server por sua própria manutenção. Como você mostrou na outra pergunta , isso funciona ...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

... e faz reduzir a fragmentação. Embora possa exigir permissões elevadas (eu não tentei como peão).

Talvez você possa fazer isso periodicamente como parte de sua própria manutenção, se isso faz você se sentir bem e / ou tem alguma evidência de que isso tenha algum impacto positivo em seu sistema.


Adicionei outra resposta resumindo o que acabamos fazendo e depois limpei os comentários anteriores aqui. Obrigado novamente por sua ajuda!
Geoff Patterson

7

Com base nas orientações da resposta de Aaron, bem como em pesquisas adicionais, aqui está um rápido resumo da abordagem adotada.

Pelo que sei, as opções para inspecionar a fragmentação das tabelas base do sistema são limitadas. Fui adiante e registrei um problema do Connect para fornecer melhor visibilidade, mas, enquanto isso, parece que as opções incluem coisas como examinar o buffer pool ou verificar o número médio de bytes por linha.

Em seguida, criei um procedimento para executar `ALTER INDEX ... REORGANIZE em todas as tabelas base do sistema . A execução deste procedimento em alguns dos nossos servidores de desenvolvimento mais (ab) usados ​​mostrou que o tamanho cumulativo das tabelas base do sistema foi cortado em até 50 GB (com ~ 5MM tabelas de usuário no sistema, portanto, claramente um caso extremo).

Uma de nossas tarefas de manutenção noturna, que ajuda a limpar muitas das tabelas de usuários criadas por vários testes e desenvolvimento de unidades, estava demorando aproximadamente 50 minutos para ser concluída. Uma combinação de sp_whoisactive, sys.dm_os_waiting_taskse DBCC PAGEmostrou que as esperas eram dominadas por E / S nas tabelas base do sistema.

Após a reorganização de todas as tabelas base do sistema, a tarefa de manutenção caiu para ~ 15 minutos. Ainda havia algumas esperas de E / S, mas elas foram significativamente diminuídas, talvez devido a uma quantidade maior de dados restantes no cache e / ou mais readaheads devido à menor fragmentação.

Portanto, minha conclusão é que adicionar ALTER INDEX...REORGANIZEtabelas de base do sistema a um plano de manutenção pode ser uma coisa útil a considerar, mas provavelmente apenas se você tiver um cenário em que um número incomum de objetos esteja sendo criado em um banco de dados.


+1 para a sua pergunta e a resposta - os internos são uma espécie de caixa preta, e você ajudou a esclarecer o que parece ser um cenário realmente desagradável para o desempenho (mesmo se o seu for um caso de risco).
Max Vernon
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.