sys.dm_db_index_physical_stats (Transact-SQL)

Aplica-se a:SQL ServerBanco de Dados SQL do AzureInstância Gerenciada de SQL do Azure

Retorna informações de tamanho e fragmentação para os dados e índices da tabela ou exibição especificada em SQL Server. Para um índice, uma linha é retornada para cada nível da árvore B em cada partição. Para um heap, uma linha é retornada para a IN_ROW_DATA unidade de alocação de cada partição. Para dados lob (objeto grande), uma linha é retornada para a LOB_DATA unidade de alocação de cada partição. Se houver dados de estouro de linha na tabela, uma linha será retornada para a ROW_OVERFLOW_DATA unidade de alocação em cada partição.

Observação

A documentação do SQL Server usa o termo árvore B geralmente em referência a índices. Em índices de armazenamento de linha, o SQL Server implementa uma árvore B+. Isso não se aplica a índices columnstore ou armazenamentos de dados na memória. Para obter mais informações, confira o Guia de arquitetura e design do índice do SQL Server e SQL do Azure.

sys.dm_db_index_physical_stats não retorna informações sobre índices columnstore com otimização de memória. Para obter informações sobre o uso de índice com otimização de memória, consulte sys.dm_db_xtp_index_stats (Transact-SQL).

Se você consultar sys.dm_db_index_physical_stats em uma instância de servidor que hospeda um grupo de disponibilidade legível réplica secundário, poderá encontrar um REDO problema de bloqueio. Isso ocorre porque essa exibição de gerenciamento dinâmico adquire um IS bloqueio na tabela ou exibição de usuário especificada que pode bloquear solicitações por um REDO thread para um X bloqueio nessa tabela ou exibição de usuário.

Convenções de sintaxe de Transact-SQL

Sintaxe

sys.dm_db_index_physical_stats (
    { database_id | NULL | 0 | DEFAULT }
  , { object_id | NULL | 0 | DEFAULT }
  , { index_id | NULL | 0 | -1 | DEFAULT }
  , { partition_number | NULL | 0 | DEFAULT }
  , { mode | NULL | DEFAULT }
)

Argumentos

database_id | NULL | 0 | PADRÃO

A ID do banco de dados. database_id é pequeno. As entradas válidas são a ID de um banco de dados, NULL, 0 ou DEFAULT. O padrão é 0. NULL, 0 e DEFAULT são valores equivalentes nesse contexto.

Especifique NULL para retornar informações para todos os bancos de dados na instância do SQL Server. Se você especificar NULL para database_id, também deverá especificar NULL para object_id, index_id e partition_number.

A função interna DB_ID pode ser especificada. Ao usar DB_ID sem especificar um nome de banco de dados, o nível de compatibilidade do banco de dados atual deve ser 90 ou maior.

object_id | NULL | 0 | PADRÃO

A ID do objeto da tabela ou exibição em que o índice está. object_id é int.

As entradas válidas são a ID de uma tabela e exibição, NULL, 0 ou DEFAULT. O padrão é 0. NULL, 0 e DEFAULT são valores equivalentes nesse contexto. A partir de SQL Server 2016 (13.x), as entradas válidas também incluem o nome da fila do agente de serviço ou o nome da tabela interna da fila. Quando os parâmetros padrão são aplicados (ou seja, todos os objetos, todos os índices etc.), as informações de fragmentação para todas as filas são incluídas no conjunto de resultados.

Especifique NULL para retornar informações de todas as tabelas e exibições no banco de dados especificado. Se você especificar NULL para object_id, também deverá especificar NULL para index_id e partition_number.

index_id | 0 | NULL | -1 | PADRÃO

A ID do índice. index_id é int. Entradas válidas são a ID de um índice, 0 se object_id for um heap, NULL, -1 ou DEFAULT. O padrão é -1. NULL, -1 e DEFAULT são valores equivalentes nesse contexto.

Especifique NULL para retornar informações de todos os índices de uma tabela base ou exibição. Se você especificar NULL para index_id, também deverá especificar NULL para partition_number.

partition_number | NULL | 0 | PADRÃO

O número da partição no objeto . partition_number é int. Entradas válidas são o partion_number de um índice ou heap, NULL, 0 ou DEFAULT. O padrão é 0. NULL, 0 e DEFAULT são valores equivalentes nesse contexto.

Especifique NULL para retornar informações de todas as partições do objeto proprietário.

partition_number é baseado em 1. Um índice ou heap não particionado partition_number definido como 1.

mode | NULL | PADRÃO

O nome do modo. O modo especifica o nível de verificação usado para obter estatísticas. mode é sysname. Entradas válidas são DEFAULT, NULL, LIMITED, SAMPLED ou DETAILED. O padrão (NULL) é LIMITED.

Tabela retornada

Nome da coluna Tipo de dados Descrição
database_id smallint Identificação do banco de dados da tabela ou exibição.

Em SQL do Azure Banco de Dados, os valores são exclusivos em um único banco de dados ou um pool elástico, mas não dentro de um servidor lógico.
object_id int Identificação de objeto da tabela ou exibição na qual o índice se encontra.
index_id int Identificação de um índice.

0 = Heap.
partition_number int Número de partição de base 1 no objeto proprietário; uma tabela, exibição ou índice.

1 = Índice ou heap não particionado.
index_type_desc nvarchar(60) Descrição do tipo de índice:

– HEAP
- ÍNDICE CLUSTERIZADO
- ÍNDICE NÃO CLUSTERIZADO
- ÍNDICE XML PRIMÁRIO
- ÍNDICE ESTENDIDO
- ÍNDICE XML
- ÍNDICE DE MAPEAMENTO COLUMNSTORE (interno)
- COLUMNSTORE DELETEBUFFER INDEX (interno)
- COLUMNSTORE DELETEBITMAP INDEX (interno)
hobt_id bigint Heap ou ID de árvore B do índice ou partição.

Para índices columnstore, essa é a ID de um conjunto de linhas que rastreia dados columnstore internos de uma partição. Os conjuntos de linhas são armazenados como heaps de dados ou árvores B. Eles têm a mesma ID de índice que o índice columnstore pai. Para obter mais informações, consulte sys.internal_partitions (Transact-SQL).
alloc_unit_type_desc nvarchar(60) Descrição do tipo de unidade de alocação:

- IN_ROW_DATA
-LOB_DATA
-ROW_OVERFLOW_DATA

A LOB_DATA unidade de alocação contém os dados armazenados em colunas do tipo text, ntext, image, varchar(max), nvarchar(max), varbinary(max)e xml. Para obter mais informações, consulte Tipos de dados (Transact-SQL).

A ROW_OVERFLOW_DATA unidade de alocação contém os dados armazenados em colunas do tipo varchar(n), nvarchar(n), varbinary(n)e sql_variant que foram enviadas para fora da linha.
index_depth tinyint Número de níveis de índice.

1 = Heap ou LOB_DATA ou ROW_OVERFLOW_DATA unidade de alocação.
index_level tinyint Nível atual do índice.

0 para níveis de folha de índice, heaps e LOB_DATA ou ROW_OVERFLOW_DATA unidades de alocação.

Maior que 0 para níveis de índice nonleaf. index_level é o mais alto no nível raiz de um índice.

Os níveis não folha de índices só são processados quando mode = DETAILED.
avg_fragmentation_in_percent float Fragmentação lógica para índices ou fragmentação de extensão para heaps na IN_ROW_DATA unidade de alocação.

O valor é medido como uma porcentagem e leva em consideração vários arquivos. Para definições de fragmentação lógica e de extensão, consulte Comentários.

0 para LOB_DATA e ROW_OVERFLOW_DATA unidades de alocação.

NULL para heaps quando mode = SAMPLED.
fragment_count bigint Número de fragmentos no nível folha de uma IN_ROW_DATA unidade de alocação. Para obter mais informações sobre fragmentos, consulte Comentários.

NULL para níveis não folha de um índice e LOB_DATA ou ROW_OVERFLOW_DATA unidades de alocação.

NULL para heaps quando mode = SAMPLED.
avg_fragment_size_in_pages float Número médio de páginas em um fragmento no nível folha de uma IN_ROW_DATA unidade de alocação.

NULL para níveis não folha de um índice e LOB_DATA ou ROW_OVERFLOW_DATA unidades de alocação.

NULL para heaps quando mode = SAMPLED.
page_count bigint Número total de páginas de índice ou dados.

Para um índice, o número total de páginas de índice no nível atual da árvore B na IN_ROW_DATA unidade de alocação.

Para um heap, o número total de páginas de dados na IN_ROW_DATA unidade de alocação.

Para LOB_DATA unidades de alocação ou ROW_OVERFLOW_DATA , número total de páginas na unidade de alocação.
avg_page_space_used_in_percent float Porcentagem média de espaço de armazenamento de dados disponível usada em todas as páginas.

Para um índice, a média se aplica ao nível atual da árvore B na IN_ROW_DATA unidade de alocação.

Para um heap, a média de todas as páginas de dados na IN_ROW_DATA unidade de alocação.

Para LOB_DATA unidades de alocação ou ROW_OVERFLOW_DATA , a média de todas as páginas na unidade de alocação.

NULL quando mode = LIMITED.
record_count bigint Número total de registros.

Para um índice, o número total de registros se aplica ao nível atual da árvore B na IN_ROW_DATA unidade de alocação.

Para um heap, o número total de registros na IN_ROW_DATA unidade de alocação.

Nota: Para um heap, o número de registros retornados dessa função pode não corresponder ao número de linhas retornadas executando um SELECT COUNT(*) em relação ao heap. Isso porque uma linha pode conter vários registros. Por exemplo, em algumas situações de atualização, uma única linha de heap pode ter um registro de encaminhamento e um registro encaminhado como resultado de uma operação de atualização. Além disso, a maioria das linhas lob grandes são divididas em vários registros no LOB_DATA armazenamento.

Para LOB_DATA unidades de alocação ou ROW_OVERFLOW_DATA , o número total de registros na unidade de alocação completa.

NULL quando mode = LIMITED.
ghost_record_count bigint Número de registros fantasmas prontos para remoção pela tarefa de limpeza fantasma na unidade de alocação.

0 para níveis não folha de um índice na IN_ROW_DATA unidade de alocação.

NULL quando mode = LIMITED.
version_ghost_record_count bigint Número de registros fantasmas retidos por uma transação de isolamento de instantâneo pendente em uma unidade de alocação.

0 para níveis não folha de um índice na IN_ROW_DATA unidade de alocação.

NULL quando mode = LIMITED.
min_record_size_in_bytes int Tamanho de registro mínimo em bytes.

Para um índice, o tamanho mínimo do registro se aplica ao nível atual da árvore B na IN_ROW_DATA unidade de alocação.

Para um heap, o tamanho mínimo do registro na IN_ROW_DATA unidade de alocação.

Para LOB_DATA unidades de alocação ou ROW_OVERFLOW_DATA , o tamanho mínimo do registro na unidade de alocação completa.

NULL quando mode = LIMITED.
max_record_size_in_bytes int Tamanho de registro máximo em bytes.

Para um índice, o tamanho máximo do registro se aplica ao nível atual da árvore B na IN_ROW_DATA unidade de alocação.

Para um heap, o tamanho máximo do registro na IN_ROW_DATA unidade de alocação.

Para LOB_DATA unidades de alocação ou ROW_OVERFLOW_DATA , o tamanho máximo do registro na unidade de alocação completa.

NULL quando mode = LIMITED.
avg_record_size_in_bytes float Tamanho de registro médio em bytes.

Para um índice, o tamanho médio do registro se aplica ao nível atual da árvore B na IN_ROW_DATA unidade de alocação.

Para um heap, o tamanho médio do registro na IN_ROW_DATA unidade de alocação.

Para LOB_DATA unidades de alocação ou ROW_OVERFLOW_DATA , o tamanho médio do registro na unidade de alocação completa.

NULL quando mode = LIMITED.
forwarded_record_count bigint Número de registros em um heap com ponteiros encaminhados a outro local de dados. (Esse estado ocorre durante uma atualização, quando não há espaço suficiente para armazenar a nova linha no local original.)

NULL para qualquer unidade de alocação diferente das IN_ROW_DATA unidades de alocação de um heap.

NULL para heaps quando mode = LIMITED.
compressed_page_count bigint O número total de páginas compactadas.

Para heaps, as páginas recém-alocadas não são compactadas por PAGE. Um heap é compactado com PAGE em duas condições especiais: quando os dados são importados em massa ou quando um heap é reconstruído. As operações DML típicas que causam alocações de página não são compactadas por PAGE. Reconstrua um heap quando o valor compressed_page_count aumentar ultrapassando o limite desejado.

Para tabelas que têm um índice clusterizado, o valor compressed_page_count indica a eficiência da compactação PAGE.
columnstore_delete_buffer_state tinyint 0 = NOT_APPLICABLE
1 = OPEN
2 = DRENAGEM
3 = FLUSHING
4 = DESATIVAR
5 = PRONTO

Aplica-se a: SQL Server 2016 (13.x) e versões posteriores, banco de dados SQL do Azure e Instância Gerenciada de SQL do Azure
columnstore_delete_buffer_state_desc nvarchar(60) NÃO VÁLIDO – o índice pai não é um índice columnstore.

OPEN – exclusores e scanners usam isso.

DRENAGEM - os exclusores estão drenando, mas os scanners ainda o usam.

FLUSHING – o buffer é fechado e as linhas no buffer estão sendo gravadas no bitmap de exclusão.

DESATIVANDO – as linhas no buffer de exclusão fechada foram gravadas no bitmap de exclusão, mas o buffer não foi truncado porque os scanners ainda o estão usando. Novos scanners não precisam usar o buffer de desativação porque o buffer aberto é suficiente.

READY – esse buffer de exclusão está pronto para uso.

Aplica-se a: SQL Server 2016 (13.x) e versões posteriores, banco de dados SQL do Azure e Instância Gerenciada de SQL do Azure
version_record_count bigint Essa é a contagem dos registros de versão de linha que estão sendo mantidos nesse índice. Essas versões de linha são mantidas pelo recurso recuperação acelerada de banco de dados.

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores e SQL do Azure Banco de Dados
inrow_version_record_count bigint Contagem de registros de versão da ADR mantidos na linha de dados para recuperação rápida.

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores e SQL do Azure Banco de Dados
inrow_diff_version_record_count bigint Contagem de registros de versão da ADR mantidos na forma de diferenças da versão base.

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores e SQL do Azure Banco de Dados
total_inrow_version_payload_size_in_bytes bigint Tamanho total em bytes dos registros de versão em linha para esse índice.

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores e SQL do Azure Banco de Dados
offrow_regular_version_record_count bigint Contagem de registros de versão sendo mantidos fora da linha de dados original.

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores e SQL do Azure Banco de Dados
offrow_long_term_version_record_count bigint Contagem de registros de versão considerados de longo prazo.

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores e SQL do Azure Banco de Dados

Observação

A documentação do SQL Server usa o termo árvore B geralmente em referência a índices. Em índices de armazenamento de linha, o SQL Server implementa uma árvore B+. Isso não se aplica a índices columnstore ou armazenamentos de dados na memória. Para obter mais informações, confira o Guia de arquitetura e design do índice do SQL Server e SQL do Azure.

Comentários

A sys.dm_db_index_physical_stats função de gerenciamento dinâmico substitui a DBCC SHOWCONTIG instrução .

Modos de verificação

O modo em que a função é executada determina o nível do exame executado para obter os dados estatísticos usados pela função. mode é especificado como LIMITED, SAMPLED ou DETAILED. A função atravessa as cadeias de páginas para as unidades de alocação que compõem as partições especificadas da tabela ou índice. sys.dm_db_index_physical_stats exige apenas um bloqueio de tabela IS (Intent-Shared, Tentativa compartilhada), independentemente do modo no qual executa.

O modo LIMITED é o mais rápido e examina o menor número de páginas. Para um índice, apenas as páginas de nível pai da árvore b (ou seja, aquelas acima do nível folha) são examinadas. Para um heap, as páginas PFS e IAM associadas são examinadas, e as páginas de dados de um heap são examinadas no modo LIMITED.

Com o modo LIMITED, compressed_page_count é NULL porque o Mecanismo de Banco de Dados examina apenas páginas não folha da árvore B e das páginas IAM e PFS do heap. Use modo SAMPLED para obter um valor estimado para compressed_page_count e use modo DETAILED para obter o valor real para compressed_page_count. O modo SAMPLED retorna estatísticas com base em uma amostra de 1 por cento de todas as páginas no índice ou heap. Os resultados em modo SAMPLED devem ser considerados aproximados. Se o índice ou heap tiver menos que 10.000 páginas, o modo DETAILED será usado em vez do SAMPLED.

O modo DETAILED examina todas as páginas e retorna todas as estatísticas.

Os modos são progressivamente mais lentos de LIMITED para DETAILED, porque mais trabalho é executado em cada modo. Para medir rapidamente o tamanho ou o nível de fragmentação de uma tabela ou índice, use o modo LIMITED. Ele é o mais rápido e não retorna uma linha para cada nível não folha na IN_ROW_DATA unidade de alocação do índice.

Usar funções do sistema para especificar valores de parâmetro

Você pode usar as funções Transact-SQL DB_ID e OBJECT_ID para especificar um valor para os parâmetros database_id e object_id . No entanto, passar valores que não são válidos para essas funções pode causar resultados não intencionais. Por exemplo, se o nome do banco de dados ou objeto não puder ser encontrado porque eles não existem ou estiverem escritos incorretamente, ambas as funções retornarão NULL. A função sys.dm_db_index_physical_stats interpreta NULL como um valor curinga que especifica todos os bancos de dados ou todos os objetos.

Além disso, a OBJECT_ID função é processada antes que a sys.dm_db_index_physical_stats função seja chamada e, portanto, é avaliada no contexto do banco de dados atual, não no banco de dados especificado em database_id. Esse comportamento pode fazer com que a OBJECT_ID função retorne um valor NULL; ou, se o nome do objeto existir no contexto do banco de dados atual e no banco de dados especificado, uma mensagem de erro poderá ser retornada. Os exemplos seguintes demonstram esses resultados não intencionais.

USE master;
GO
-- In this example, OBJECT_ID is evaluated in the context of the master database.
-- Because Person.Address does not exist in master, the function returns NULL.
-- When NULL is specified as an object_id, all objects in the database are returned.
-- The same results are returned when an object that is not valid is specified.
SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'AdventureWorks2022'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- This example demonstrates the results of specifying a valid object name
-- that exists in both the current database context and
-- in the database specified in the database_id parameter of the
-- sys.dm_db_index_physical_stats function.
-- An error is returned because the ID value returned by OBJECT_ID does not
-- match the ID value of the object in the specified database.
CREATE DATABASE Test;
GO
USE Test;
GO
CREATE SCHEMA Person;
GO
CREATE Table Person.Address(c1 int);
GO
USE AdventureWorks2022;
GO
SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'Test'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- Clean up temporary database.
DROP DATABASE Test;
GO

Melhor prática

Sempre verifique se uma ID válida é retornada quando você usa DB_ID ou OBJECT_ID. Por exemplo, ao usar , especifique OBJECT_IDum nome de três partes, como OBJECT_ID(N'AdventureWorks2022.Person.Address'), ou teste o valor retornado pelas funções antes de usá-las na sys.dm_db_index_physical_stats função . Os exemplos A e B a seguir demonstram um modo seguro de especificar identificações de banco de dados e objeto.

Detectar fragmentação

A fragmentação ocorre por meio dos processos de modificações de dados (instruções INSERT, UPDATE e DELETE) feitas na tabela e, portanto, nos índices definidos na tabela. Como essas modificações normalmente não são distribuídas igualmente entre as linhas da tabela e dos índices, a plenitude de cada página pode variar ao longo do tempo. Para consultas que examinam parte dos índices de uma tabela ou todos eles, esse tipo de fragmentação pode causar leituras de página adicionais. Isso impede o exame paralelo de dados.

O nível de fragmentação de um índice ou heap é mostrado na coluna avg_fragmentation_in_percent. Para heaps, o valor representa a fragmentação de extensão do heap. Para índices, o valor representa a fragmentação lógica do índice. Ao contrário DBCC SHOWCONTIGde , os algoritmos de cálculo de fragmentação em ambos os casos consideram o armazenamento que abrange vários arquivos e, portanto, são precisos.

Fragmentação lógica

É a porcentagem de páginas com problema nas páginas de folha de um índice. Uma página fora de ordem é aquela para a qual a próxima página física alocada no índice não é a apontada pelo ponteiro de próxima página na página folha atual.

Fragmentação de extensão

É a porcentagem de extensões com problema nas páginas de folha de um heap. Uma extensão fora de ordem é aquela para a qual a extensão que contém a página atual de um heap não é fisicamente a próxima extensão após a extensão que contém a página anterior.

O valor de avg_fragmentation_in_percent deve ser o mais próximo possível de zero para um máximo desempenho. Porém, valores de 0% a 10% podem ser aceitáveis. Podem ser usados todos os métodos de redução de fragmentação, como reconstruir, reorganizar ou recriar, para reduzir esses valores. Para obter mais informações sobre como analisar o grau de fragmentação em um índice, consulte Reorganizar e recompilar índices.

Reduzir a fragmentação em um índice

Quando um índice estiver fragmentado de forma que a fragmentação afete o desempenho da consulta, há três opções para reduzir a fragmentação:

  • Descartar e recriar o índice clusterizado.

    Recriar um índice clusterizado redistribui os dados e resulta em páginas de dados completas. O nível de preenchimento pode ser configurado usando a opção FILLFACTOR em CREATE INDEX. As desvantagens desse método são que o índice permanece offline durante o ciclo de descarte e recriação e que a operação é atômica. Se a criação do índice for interrompida, ele não será recriado. Para obter mais informações, veja CREATE INDEX (Transact-SQL).

  • Use ALTER INDEX REORGANIZE, a substituição de DBCC INDEXDEFRAG, para reordenar as páginas de nível folha do índice em uma ordem lógica. Como essa operação é online, o índice permanecerá disponível enquanto a instrução estiver sendo executada. A operação também pode ser interrompida sem perda do trabalho já concluído. A desvantagem nesse método é que ele não faz um trabalho tão bom de reorganizar os dados como uma operação de recompilação de índice e não atualiza estatísticas.

  • Use ALTER INDEX REBUILD, a substituição de DBCC DBREINDEX, para recompilar o índice online ou offline. Para mais informações, consulte ALTERAR ÍNDICE (Transact-SQL).

A fragmentação por si só não é um motivo suficiente para reorganizar ou recompilar um índice. O efeito principal da fragmentação é que ela reduz a velocidade da taxa de transferência read-ahead da página durante os exames de índice. O resultado é tempos de resposta mais lentos. Se a carga de trabalho de consulta em uma tabela ou índice fragmentado não envolver verificações, pois a carga de trabalho é principalmente pesquisas singleton, a remoção da fragmentação pode não ter efeito.

Observação

Executar DBCC SHRINKFILE ou DBCC SHRINKDATABASE pode introduzir fragmentação se um índice for parcial ou completamente movido durante a operação de redução. Assim, se for necessário executar uma operação de redução, você deverá fazer isso antes da remoção da fragmentação.

Reduzir a fragmentação em um heap

Para reduzir a extensão da fragmentação de um heap, crie um índice clusterizado na tabela e descarte o índice. Isso redistribui os dados enquanto o índice clusterizado é criado. E também otimiza o máximo possível esse processo, enquanto considera a distribuição de espaço livre disponível no banco de dados. Quando o índice clusterizado é descartado para recriar o heap, os dados não são movidos e permanecem na posição ideal. Para obter informações sobre como executar essas operações, consulte CREATE INDEX e DROP INDEX.

Cuidado

Criar e descartar um índice clusterizado em uma tabela recompila todos os índices não clusterizados nessa tabela duas vezes.

Compactar dados de objeto grande

Por padrão, a instrução ALTER INDEX REORGANIZE compacta páginas que contêm dados LOB (objetos grandes). Como as páginas LOB não são desalocadas quando vazias, a compactação desses dados pode melhorar o uso do espaço em disco se muitos dados LOB tiverem sido excluídos ou uma coluna LOB for descartada.

Reorganizar um índice clusterizado especificado compacta todas as colunas LOB contidas no índice clusterizado. Reorganizar um índice não clusterizado compacta todas as colunas LOB não-chave (incluídas) no índice. Quando ALL é especificado na instrução, todos os índices associados à tabela ou exibição especificada são reorganizados. Além disso, todas as colunas LOB associadas ao índice clusterizado, à tabela subjacente ou ao índice não clusterizado com colunas incluídas são compactadas.

Avaliar o uso do espaço em disco

A coluna avg_page_space_used_in_percent indica o preenchimento da página. Para obter o uso ideal de espaço em disco, esse valor deve estar próximo de 100% para um índice que não tenha muitas inserções aleatórias. No entanto, um índice que tem muitas inserções aleatórias e tem páginas muito completas tem um número maior de divisões de página. Isso causa mais fragmentação. Por isso, para reduzir as divisões de página, o valor deve ser menor que 100%. A recriação de um índice com a opção FILLFACTOR especificada permite que o preenchimento da página seja alterado para atender ao padrão de consulta do índice. Para obter mais informações sobre o fator de preenchimento, consulte Especificar fator de preenchimento para um índice. Além disso, ALTER INDEX REORGANIZE compactará um índice tentando preencher páginas para o FILLFACTOR especificado pela última vez. Isso aumenta o valor em avg_space_used_in_percent. ALTER INDEX REORGANIZE não pode reduzir a integridade da página. Em vez disso, o índice deverá ser recriado.

Avaliar fragmentos de índice

Um fragmento é composto de páginas de folha fisicamente consecutivas no mesmo arquivo de uma unidade de alocação. Um índice tem pelo menos um fragmento. O máximo de fragmentos que um índice pode ter é igual ao número de páginas no nível folha do índice. Fragmentos maiores indicam que menos E/S de disco é necessária para ler o mesmo número de páginas. Por isso, quanto maior o valor avg_fragment_size_in_pages, melhor o desempenho de exame de intervalo. Os valores avg_fragment_size_in_pages e avg_fragmentation_in_percent são inversamente proporcionais um ao outro. Por isso, a reconstrução ou a reorganização de um índice deve reduzir a quantidade de fragmentação e aumentar o tamanho do fragmento.

Limitações e restrições

Não retorna dados para índices columnstore clusterizados.

Permissões

Requer as seguintes permissões:

  • Permissão CONTROL no objeto especificado no banco de dados.

  • Permissão VIEW DATABASE STATE ou VIEW DATABASE PERFORMANCE STATE (SQL Server 2022) para retornar informações sobre todos os objetos dentro do banco de dados especificado, usando o objeto curinga @object_id=NULL.

  • Permissão VIEW SERVER STATE ou VIEW SERVER PERFORMANCE STATE (SQL Server 2022) para retornar informações sobre todos os bancos de dados usando o curinga do banco de dados @database_id = NULL.

Conceder VIEW DATABASE STATE permite que todos os objetos no banco de dados sejam retornados, independentemente de qualquer permissão CONTROL negada a objetos específicos.

Negar VIEW DATABASE STATE impede que todos os objetos do banco de dados sejam retornados, independentemente de qualquer permissão CONTROL concedida a objetos específicos. Além disso, quando o curinga do banco de dados @database_id=NULL é especificado, o banco de dados é omitido.

Para obter mais informações, consulte Exibições e funções de gerenciamento dinâmico (Transact-SQL).

Exemplos

a. Retornar informações sobre uma tabela especificada

O exemplo a seguir retorna as estatísticas de tamanho e fragmentação de todos os índices e partições da tabela Person.Address. O modo de exame é definido como 'LIMITED' para oferecer melhor desempenho e limitar as estatísticas retornadas. A execução dessa consulta requer, no mínimo, a permissão CONTROL na tabela Person.Address.

DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
  
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.Person.Address');
  
IF @db_id IS NULL
BEGIN;
    PRINT N'Invalid database';
END;
ELSE IF @object_id IS NULL
BEGIN;
    PRINT N'Invalid object';
END;
ELSE
BEGIN;
    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , 'LIMITED');
END;
GO

B. Retornar informações sobre um heap

O exemplo a seguir retorna todas as estatísticas para o heap dbo.DatabaseLog no banco de dados AdventureWorks2022. Como a tabela contém dados LOB, uma linha é retornada para a unidade de alocação LOB_DATA, além da linha retornada para IN_ROW_ALLOCATION_UNIT que está armazenando as páginas de dados do heap. A execução dessa consulta requer, no mínimo, a permissão CONTROL na tabela dbo.DatabaseLog.

DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.dbo.DatabaseLog');
IF @object_id IS NULL
BEGIN;
    PRINT N'Invalid object';
END;
ELSE
BEGIN;
    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, 0, NULL , 'DETAILED');
END;
GO

C. Retornar informações para todos os bancos de dados

O exemplo a seguir retorna todas as estatísticas para todas as tabelas e índices dentro da instância do SQL Server especificando o curinga NULL para todos os parâmetros. A execução desta consulta requer a permissão VIEW SERVER STATE.

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);
GO

D. Usar sys.dm_db_index_physical_stats em um script para recompilar ou reorganizar índices

O exemplo a seguir reorganiza ou reconstrói automaticamente em um banco de dados todas as partições que têm uma fragmentação média de 10%. A execução desta consulta requer a permissão VIEW DATABASE STATE. Este exemplo especifica DB_ID como o primeiro parâmetro sem especificar um nome de banco de dados. Um erro será gerado se o banco de dados atual tiver um nível de compatibilidade igual ou inferior a 80. Para resolver o erro, substitua DB_ID() por um nome de banco de dados válido. Para obter mais informações sobre os níveis de compatibilidade do banco de dados, consulte ALTER DATABASE Nível de compatibilidade (Transact-SQL).

-- Ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;

DECLARE @objectid INT;
DECLARE @indexid INT;
DECLARE @partitioncount BIGINT;
DECLARE @schemaname NVARCHAR(130);
DECLARE @objectname NVARCHAR(130);
DECLARE @indexname NVARCHAR(130);
DECLARE @partitionnum BIGINT;
DECLARE @partitions BIGINT;
DECLARE @frag FLOAT;
DECLARE @command NVARCHAR(4000);

-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT object_id AS objectid,
    index_id AS indexid,
    partition_number AS partitionnum,
    avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0
    AND index_id > 0;

-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR
FOR
SELECT *
FROM #work_to_do;

-- Open the cursor.
OPEN partitions;

-- Loop through the partitions.
WHILE (1 = 1)
BEGIN;

    FETCH NEXT
    FROM partitions
    INTO @objectid,
        @indexid,
        @partitionnum,
        @frag;

    IF @@FETCH_STATUS < 0
        BREAK;

    SELECT @objectname = QUOTENAME(o.name),
        @schemaname = QUOTENAME(s.name)
    FROM sys.objects AS o
    INNER JOIN sys.schemas AS s
        ON s.schema_id = o.schema_id
    WHERE o.object_id = @objectid;

    SELECT @indexname = QUOTENAME(name)
    FROM sys.indexes
    WHERE object_id = @objectid
        AND index_id = @indexid;

    SELECT @partitioncount = count(*)
    FROM sys.partitions
    WHERE object_id = @objectid
        AND index_id = @indexid;

    -- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
    IF @frag < 30.0
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';

    IF @frag >= 30.0
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';

    IF @partitioncount > 1
        SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS NVARCHAR(10));

    EXEC (@command);

    PRINT N'Executed: ' + @command;
END;

-- Close and deallocate the cursor.
CLOSE partitions;

DEALLOCATE partitions;

-- Drop the temporary table.
DROP TABLE #work_to_do;
GO

E. Use sys.dm_db_index_physical_stats para mostrar o número de páginas compactadas por página

O exemplo seguinte mostra como exibir e comparar o número total de páginas em relação às páginas que são compactadas por linha e página. Estas informações podem ser usadas para determinar o benefício que a compactação está fornecendo para um índice ou tabela.

SELECT o.name,
    ips.partition_number,
    ips.index_type_desc,
    ips.record_count,
    ips.avg_record_size_in_bytes,
    ips.min_record_size_in_bytes,
    ips.max_record_size_in_bytes,
    ips.page_count,
    ips.compressed_page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
INNER JOIN sys.objects o
    ON o.object_id = ips.object_id
ORDER BY record_count DESC;

F. Usar sys.dm_db_index_physical_stats no modo SAMPLED

O exemplo a seguir mostra como o modo SAMPLED retorna um aproximado que é diferente dos resultados do modo DETAILED.

CREATE TABLE t3 (
    col1 INT PRIMARY KEY,
    col2 VARCHAR(500)
    )
    WITH (DATA_COMPRESSION = PAGE);
GO

BEGIN TRANSACTION

DECLARE @idx INT = 0;

WHILE @idx < 1000000
BEGIN
    INSERT INTO t3 (col1, col2)
    VALUES (
        @idx,
        REPLICATE('a', 100) + CAST(@idx AS VARCHAR(10)) + REPLICATE('a', 380)
        )

    SET @idx = @idx + 1
END

COMMIT;
GO

SELECT page_count,
    compressed_page_count,
    forwarded_record_count,
    *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'SAMPLED');

SELECT page_count,
    compressed_page_count,
    forwarded_record_count,
    *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'DETAILED');

G. Consultar filas do agente de serviço para fragmentação de índice

Aplica-se a: SQL Server 2016 (13.x) e versões posteriores.

O exemplo a seguir mostra como consultar filas do agente de servidor para fragmentação.

--Using queue internal table name
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('sys.queue_messages_549576996'), DEFAULT, DEFAULT, DEFAULT);

--Using queue name directly
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('ExpenseQueue'), DEFAULT, DEFAULT, DEFAULT);

Confira também