Por que meu banco de dados ainda está fragmentado depois que reconstruí e reindexo tudo?

41

Eu tenho um banco de dados que tentei desfragmentar todas as tabelas ao mesmo tempo executando este T-SQL:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

E depois copiar e colar a saída em uma nova janela de consulta e executá-la. Não obtive erros, mas ainda tenho fragmentação. Tentei executar os dois comandos separadamente também e ainda tenho fragmentação. Nota: Fui informado de que o REORGANIZEAaron é desnecessário e sei que poderia usar o sql dinâmico para automatizar isso.

Eu executei isso para determinar que ainda tenho fragmentação:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

E eu tenho:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

Sei que estou perdendo algo realmente básico, mas não sei o quê.

Justin Dearing
fonte
Quais erros você recebeu? Também há uma razão para você reorganizar e reconstruir a mesma coisa?
Shawn Melton
Shawn, peço desculpas pela falta de uma palavra. Eu tenho erros. Quanto ao motivo de executar os dois comandos, fiz isso depois de tentar cada comando individualmente. Eu atualizei minhas perguntas.
Justin Dearing

Respostas:

38

As mesas são pequenas. As contagens de páginas em suas tabelas são:

11, 8, 6, 5, 13, 8, 10

Eles ocupam 480kb no total. Não há literalmente nada para desfragmentar.

Edit: Isso justifica um pouco mais de explicação.

Geralmente, uma nova tabela ou índice é alocada para as 8 primeiras páginas de uma extensão mista e não uniforme. Portanto, é possível que cada uma das 8 primeiras páginas seja alocada de diferentes extensões mistas. Uma tabela ou índice que consome 8 páginas pode, portanto, ter 8 fragmentos, 1 em cada uma das 8 extensões mistas diferentes.

Os scripts de desfragmentação mais usados ​​(alguns exemplos vinculados abaixo) tendem a excluir pequenas tabelas por causa disso. IIRC, <500 páginas estão em um ou em ambos. Nesses tamanhos, há muito pouco benefício em desfragmentar e os números de fragmentação são potencialmente distorcidos pelas alocações de extensão mista.

Mark Storey-Smith
fonte
Ok, isso é satisfatório, a menos que alguém tenha uma resposta melhor, vou marcar a sua como correta.
Justin Dearing
3
+1 Concordou com Mark. Preocupe-se com a fragmentação quando você realmente tiver alguns dados. :-)
Aaron Bertrand
Eu entendo completamente o que você está dizendo. Mas apenas por pura curiosidade, é porque o mecanismo db simplesmente não pode desfragmentar tão poucas páginas? Quero dizer, deve haver uma razão para isso.
Thomas Stringer
3
Não é que não possa, mas por que isso se incomodaria? Fazer isso terá pouco ou nenhum impacto nas E / S - especialmente porque as tabelas tão pequenas são quase garantidas na memória.
Aaron Bertrand
11
Somente. Parece estranho, só isso. Digamos que estou escrevendo um aplicativo para verificar e relatar a fragmentação do índice, teria que adicionar lógica adicional para testar não apenas a porcentagem de fragmentos, mas também a quantidade de páginas para que não haja alarmes falsos.
Thomas Stringer
19

Citação de " Práticas recomendadas para desfragmentação de índice do Microsoft SQL Server 2000 ":

"A fragmentação afeta a E / S do disco. Portanto, concentre-se nos índices maiores porque é menos provável que suas páginas sejam armazenadas em cache pelo SQL Server. Use a contagem de páginas relatada pelo DBCC SHOWCONTIG para obter uma idéia do tamanho dos índices (cada página é 8 KB de tamanho). Geralmente, você não deve se preocupar com níveis de fragmentação de índices com menos de 1.000 páginas. Nos testes, índices contendo mais de 10.000 páginas obtiveram ganhos de desempenho, com os maiores ganhos em índices com significativamente mais páginas (maior de 50.000 páginas) ".

Portanto, esse tipo de resposta à sua pergunta e apóia as respostas de Mark e Aaron.

Você pode encontrar boas informações sobre fragmentação de índice nos seguintes artigos de Brent Ozar:

Também ... um oceano de ótimas informações sobre índices em geral (também sobre problemas de fragmentação) pode ser encontrado no blog de Kimberly Tripp .

Marian
fonte
12

Isso não serve para responder à sua pergunta, mas nunca caberá em um comentário. Você pode criar esse script dinamicamente sem precisar copiar e colar a saída em outra janela. Tendo em conta que não há absolutamente nenhuma razão para REORGANIZEe, em seguida REBUILD:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;
Aaron Bertrand
fonte
Aaron, obrigado por apontar o sql dinâmico, estou bem ciente do sql dinâmico, não automatizaria a solução até que funcionasse. Outros que estão lendo isso provavelmente devem estar cientes.
Justin Dearing