TL\DR
Estou procurando uma maneira de identificar com eficiência o objeto localizado mais próximo do final de um arquivo de dados do SQL Server . Essa abordagem precisa manter o desempenho em relação a arquivos de dados grandes.
O que eu tenho até agora
A consulta a seguir utiliza uma Função de Gerenciamento Dinâmico não documentada fornecida com o SQL 2012: sys.dm_db_database_page_allocations
; este DMF fornece um equivalente aproximado do DBCC IND
comando.
A consulta a seguir identifica o último objeto em um determinado arquivo de dados ( Aviso: não execute isso em um banco de dados maior que 25 GB, a menos que você queira cancelá-lo em algum momento ):
-- Return object with highest Extent Page ID
SELECT files.name as logical_file_name
, files.physical_name as physical_file_name
, OBJECT_SCHEMA_NAME(object_id) + N'.' + OBJECT_NAME(object_id) AS object_name
, alloc.*
FROM sys.dm_db_database_page_allocations(DB_ID(), NULL, NULL, NULL, NULL) alloc
INNER JOIN sys.database_files files
ON alloc.extent_file_id = files.file_id
WHERE is_allocated = 1
AND files.name = 'Logical_FileName'
ORDER BY files.name , files.physical_name, extent_page_id DESC
O que há de errado com essa abordagem
Como o Aviso acima indica, essa consulta será executada mais lentamente à medida que o tamanho do banco de dados aumenta porque a função é realmente projetada para uma abordagem direcionada para examinar um objeto específico e não um arquivo de dados específico em questão. Ao passar os NULL
parâmetros como eu fiz, essa função provavelmente itera por todos os objetos dentro do banco de dados nos bastidores e cospe a saída combinada. Isso realiza o que eu preciso, mas o faz de uma maneira muito forçada que não se presta a otimizações.
O que estou pedindo
Espero que haja uma maneira de iterar pelas cadeias GAM, SGAM e/ou IAM para identificar rapidamente o objeto no final de um determinado arquivo de dados. Estou assumindo que tenho que empurrar essa abordagem para fora do TSQL para algo como o PowerShell e voltar a usar chamadas DBCC PAGE , ou algo dessa natureza, percorrendo mapas de alocação de página para descobrir qual é o último objeto de um determinado arquivo de dados. ... e espero que alguém já tenha lançado esse código ou conheça essas estruturas e/ou a saída desses procedimentos não documentados melhor do que eu.
Por que eu preciso disso?
Esta é a pergunta inevitável que muitos farão, então vou responder logo de cara. O projeto em que estou trabalhando é para acelerar um sistema legado, mas depois de consolidar várias tabelas de heap (o que foi um pesadelo por outros motivos), agora tenho muito espaço livre nos meus dados arquivos. Eu quero liberar esse espaço de volta para o sistema operacional, no entanto, a abordagem tradicional de migrar objetos para um arquivo de dados diferente não é viável neste estágio porque não tenho espaço livre suficiente para trabalhar no sistema (até que eu capaz de liberar mais espaço deste arquivo de dados).
Recorri a desabilitar o crescimento de arquivos e executar um DBCC SHRINKFILE TRUNCATEONLY
comando todas as noites para liberar todas as páginas abertas no final do arquivo de dados, mas esse é um processo lento e árduo que pode funcionar com tanta frequência quanto não. Espero identificar quais são os objetos no final do arquivo para que eu possa reconstruí-los manualmente e liberar espaço em um cronograma mais rápido.
Em suma
Existe uma maneira de identificar rapidamente o nome do objeto localizado no final de um determinado arquivo de dados? O método que estou empregando agora não está atendendo às minhas necessidades e estou aberto a usar qualquer abordagem disponível.
Eu acho que isso vai fazer isso. Esse código basicamente faz o seguinte:
DBCC SHRINKFILE
comando que liberará apenas o espaço em branco restante no final do arquivo de volta ao sistema operacional (que deve ser imediato) e seja efetivamente equivalente aoDBCC SHRINKFILE
usoTRUNCATEONLY
Isso está aninhado em um cursor que itera por meio de IDs de página dos arquivos de dados no banco de dados e é executado rapidamente com base em meus testes localizados. Também adicionei funcionalidade para identificar se o final de um arquivo de dados está ocupado por páginas que não são reservadas por tabelas ou índices, como uma página do IAM ou PFS.
O código a seguir verifica cada página do banco de dados, do número de página mais alto ao mais baixo, para ver se ela está alocada. Depois de encontrar a primeira página alocada, ele mostra o objeto associado a essa página. Não é garantido que funcione, pois a última página alocada pode não fazer referência a um objeto real; no entanto, deve funcionar na maioria das vezes .
Obtemos o número de páginas alocadas para o file_id fornecido no banco de dados atual e, em seguida, usamos um loop para inspecionar cada página via
DBCC PAGE
, salvando essa saída em uma tabela temporária. A tabela temporária é então unida parasys.all_objects
obter o nome do objeto ao qual a página está alocada.No meu equipamento de teste, vejo os seguintes resultados:
A
#dbcrep
tabela temporária contém os seguintes detalhes: