SQL Server controlla lo spazio su disco prima di allocare una nuova pagina?
-
01-11-2019 - |
Domanda
Ho una scommessa con il mio vecchio capo. Scommetto che SQL Server, quando alloca una nuova estensione, si alloca sempre dal pool di buffer e non controlla mai se c'è un posto sul disco in cui l'allocazione potrebbe essere archiviata. In sostanza, contesta che SQL Server dovrebbe verificare lo spazio disponibile sul LUN prima di assegnare una pagina. Questo sembra sbagliato, dal momento che potrei mettere il mio deposito sulla luna, il che causerebbe una grave latenza. Sento che vuole davvero che SQL Server porti sempre in una pagina dal disco in primo luogo e quindi esegui le attività DML.
Ecco la mia "prova" che ha torto. Se non sei d'accordo con la mia "prova", allora rispondi sicuramente con una migliore!
Creiamo un database e una tabella banali. Il modello di recupero del database verrà impostato su Simple e Auto_Create_Statistics verrà interrotto, al fine di ridurre al minimo il bloat del record di registro.
Prima di iniziare, lasciami divulgare la versione di SQL Server che sto usando.
SELECT @@VERSION; ------------------------------------------------------------------------------------- Microsoft SQL Server 2012 - 11.0.2100.60 (X64) Developer Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1)
Ora, il codice ...
USE master; GO IF DATABASEPROPERTYEX(N'PageAllocDemo' , N'Version') > 0 BEGIN ALTER DATABASE PageAllocDemo SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE PageAllocDemo; END; GO CREATE DATABASE PageAllocDemo GO USE PageAllocDemo; GO SET NOCOUNT ON; GO -- Set the database to SIMPLE and turn off log generating crapola ALTER DATABASE PageAllocDemo SET RECOVERY SIMPLE; GO ALTER DATABASE PageAllocDemo SET AUTO_CREATE_STATISTICS OFF; GO CREATE TABLE dbo.X ( c1 INT IDENTITY (1,1) ) ON [PRIMARY]; GO
Ora, controlliamo quante pagine sono state assegnate? Sospetto zero, poiché abbiamo creato solo una "tabella logica", nel nostro caso un mucchio vuoto.
-- How many pages are allocated to our table? DBCC IND (PageAllocDemo,X,-1); GO
Ora, cancella il registro.
-- Clear the log CHECKPOINT; GO
Cosa c'è attualmente nel registro?
-- What is in the log right now? SELECT * FROM fn_dblog(NULL,NULL); GO /* --------------------------------------- -- Operation -------------- Context --- --------------------------------------- LOP_BEGIN_CKPT LCX_NULL LOP_XACT_CKPT LCX_BOOT_PAGE_CKPT LOP_END_CKPT LCX_NULL */
Questo è previsto, poiché siamo nel semplice modello di recupero. Ora creeremo una transazione esplicita che inserirà un solo record nella nostra tabella; ma, prima di farlo, apriremo il monitoraggio del processo e filtrano per il nostro file MDF e LDF, nonché il PID per il processo SQL Server.
Inizia la transazione:
BEGIN TRAN INSERT INTO dbo.X DEFAULT VALUES; GO
Il monitor di processo mostra due scritture nel file di registro delle transazioni.
Controlliamo i record di registro.
-- What is in the log right now? SELECT * FROM fn_dblog(NULL,NULL); /* I omitted all the log records for PFS, GAM, SGAM, etc. --------------------------------------------------------------- -- Operation -------------- Context ------- Transaction ID --- --------------------------------------------------------------- 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 */
Ometto le allocazioni di bit map e PFS e possiamo vedere che una pagina è allocata e una riga viene inserita come si aspetterebbe.
Quante pagine sono assegnate al nostro heap?
-- How many pages are allocated to our table? DBCC IND (PageAllocDemo,X,-1); GO /* One IAM page and one data page and nothing else --------------------------------- PageFID PagePID IAMFID IAMPID ------- ----------- ------ ------ 1 264 NULL NULL 1 231 1 264 */
Questo è come previsto. Abbiamo una pagina IAM e una pagina di dati. Ora, la nostra penultima azione sta commettendo la transazione. Mi aspetto che a questo punto si verifichi un flush di blocco di tronchi da 512b.
COMMIT TRAN;
Finiamo la "prova" con un'operazione di checkpoint. Finora, nulla è stato impegnato nel file di dati solo nel file di registro.
CHECKPOINT; GO
Cool, le pagine di dati sono state arrossate sul disco come previsto.
La mia conclusione, dalle prove del monitor di processo è che SQL Server alloca in memoria, aggiunge il record in memoria e commette la pagina al disco tutto senza controllare nulla a livello di archiviazione.
Qualcuno si oppone a questa ipotesi? Se sì, perché?
Nessuna soluzione corretta