Fiz uma aposta com meu antigo chefe. Aposto com ela que o SQL Server, ao alocar uma nova extensão, sempre aloca do buffer pool e nunca verifica se existe algum lugar no disco onde a alocação possa ser armazenada. Essencialmente, ela contesta que o SQL Server deve verificar o espaço disponível no LUN antes de alocar uma página. Isso parece errado, já que eu poderia colocar meu armazenamento na lua, o que causaria uma latência séria. Eu sinto que ela realmente deseja que o SQL Server sempre traga uma página do disco primeiro e depois execute a (s) tarefa (s) DML.
Aqui está a minha "prova" de que ela está errada. Se você discordar da minha "prova", então, por favor, responda com uma melhor!
Vamos criar um banco de dados e uma tabela triviais. O modelo de recuperação do banco de dados será definido como SIMPLE e AUTO_CREATE_STATISTICS será desativado para minimizar o inchaço do registro de log.
Antes de começarmos, deixe-me divulgar a versão do SQL Server que estou usando.
SELECIONE @@VERSÃO; -------------------------------------------------- ----------------------------------- Microsoft SQL Server 2012 - 11.0.2100.60 (X64) Developer Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pack 1)
Agora, o código...
USE mestre; VAI IF DATABASEPROPERTYEX(N'PageAllocDemo' , N'Version') > 0 COMEÇAR ALTER DATABASE PageAllocDemo SET SINGLE_USER COM ROLLBACK IMEDIATO; DROP DATABASE PageAllocDemo; FIM; VAI CREATE DATABASE PageAllocDemo VAI USE PageAllocDemo; VAI SET NOCOUNT ON; VAI -- Defina o banco de dados como SIMPLE e desative o crapola de geração de log ALTER DATABASE PageAllocDemo SET RECUPERAÇÃO SIMPLES; VAI ALTER DATABASE PageAllocDemo SET AUTO_CREATE_STATISTICS OFF; VAI CRIAR TABELA dbo.X ( c1 IDENTIDADE INT (1,1) ) EM [PRIMÁRIO]; VAI
Agora, vamos verificar quantas páginas foram alocadas? Suspeito de zero, pois criamos apenas uma "tabela lógica", no nosso caso um heap vazio.
-- Quantas páginas estão alocadas em nossa tabela? DBCC IND (PageAllocDemo,X,-1); VAI
Agora, limpe o registro.
-- Limpa o registro PONTO DE VERIFICAÇÃO; VAI
O que está atualmente no log?
-- O que está no log agora? SELECT * FROM fn_dblog(NULL,NULL); VAI /* --------------------------------------- -- Operação -------------- Contexto --- --------------------------------------- LOP_BEGIN_CKPT LCX_NULL LOP_XACT_CKPT LCX_BOOT_PAGE_CKPT LOP_END_CKPT LCX_NULL */
Isso é esperado, pois estamos no modelo de recuperação SIMPLES. Vamos agora criar uma transação explícita que irá inserir um e apenas um registro em nossa tabela; mas, antes disso, vamos abrir o Process Monitor e filtrar nosso arquivo MDF e LDF, bem como o PID para o processo do SQL Server.
Inicie a transação:
INICIAR TRAN INSERIR NOS VALORES PADRÃO dbo.X; VAI
O Process Monitor mostra duas gravações no arquivo de log de transações.
Vamos verificar os registros de log.
-- O que está no log agora? SELECT * FROM fn_dblog(NULL,NULL); /* Omiti todos os registros de log para PFS, GAM, SGAM, etc. -------------------------------------------------- ------------- -- Operação -------------- Contexto ------- ID da transação --- -------------------------------------------------- ------------- LOP_BEGIN_XACT LCX_NULL 0000:0000030e LOP_BEGIN_XACT LCX_NULL 0000:0000030f LOP_FORMAT_PAGE LCX_HEAP 0000:0000030f LOP_COMMIT_XACT LCX_NULL 0000:0000030f LOP_INSERT_ROWS LCX_HEAP 0000:0000030e LOP_COMMIT_XACT LCX_NULL 0000:0000030e */
Eu omito o mapa de bits e as alocações de PFS e podemos ver que uma página é alocada e uma linha é inserida como seria de esperar.
Quantas páginas estão alocadas em nosso heap?
-- Quantas páginas estão alocadas em nossa tabela? DBCC IND (PageAllocDemo,X,-1); VAI /* Uma página IAM e uma página de dados e nada mais ---------------------------------- PáginaFID PáginaPID IAMFID IAMPID ------- ----------- ------ ------ 1 264 NULO NULO 1 231 1 264 */
Isso é como previsto. Temos uma página IAM e uma página de dados. Agora, nossa penúltima ação é confirmar a transação. Espero que ocorra uma descarga de bloco de log 512B neste ponto.
COMEÇAR TRAN;
Terminemos a "prova" com uma operação de ponto de verificação. Até agora, nada foi confirmado no arquivo de dados apenas no arquivo de log.
PONTO DE VERIFICAÇÃO; VAI
Legal, as páginas de dados foram liberadas para o disco conforme o esperado.
Minha conclusão, a partir da evidência do Process Monitor, é que o SQL Server aloca na memória, adiciona o registro na memória e confirma a página no disco sem verificar nada no nível de armazenamento.
Alguém se opõe a esta hipótese? Se sim, por quê?
Não há necessidade de verificar o espaço em disco ao alocar uma nova extensão para um objeto. O SQL Server já possui esse espaço no disco. Ele sabe quais páginas dentro de seu arquivo de dados são alocadas e quais não são, então não há necessidade de verificar se nós possuímos as páginas na medida em que sabemos que já possuímos. Ele simplesmente alocará espaço no buffer pool e gravará os dados na memória e, em seguida, sobrescreverá o que estiver nesse espaço no disco quando o ponto de verificação ocorrer.
A única vez que o SQL Server se preocupa em ver quanto espaço livre há no disco é quando ele está realmente expandindo o arquivo de dados.