Esiste un modo per determinare il file esatto che contiene un'unità di allocazione in un filegroup di più file?


13

Speravo di avere una visione granulare di quali file di database contenessero quali unità di allocazione per i vari HoBT (sia allineati che non allineati) che vivono in un database.

La query che ho sempre usato (vedi sotto) mi è servita bene fino a quando non abbiamo iniziato a creare più file di dati per filegroup e sono solo in grado di capire come diventare granulare come il livello del filegroup.

select 
    SchemaName = sh.name, 
    TableName = t.name, 
    IndexName = i.name, 
    PartitionNumber = p.partition_number,
    IndexID = i.index_id,
    IndexDataspaceID = i.data_space_id,
    AllocUnitDataspaceID = au.data_space_id,
    PartitionRows = p.rows
from sys.allocation_units au
join sys.partitions p
    on au.container_id = p.partition_id
join sys.indexes i 
    on i.object_id = p.object_id
    and i.index_id = p.index_id
join sys.tables t 
    on p.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
where sh.name != 'sys'
    and au.type = 2
union all 
select 
    sh.name, 
    t.name, 
    i.name, 
    p.partition_number,
    i.index_id,
    i.data_space_id,
    au.data_space_id,
    p.rows
from sys.allocation_units au
join sys.partitions p
    on au.container_id = p.hobt_id
join sys.indexes i 
    on i.object_id = p.object_id
    and i.index_id = p.index_id
join sys.tables t 
    on p.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
where sh.name != 'sys'
    and au.type in (1,3)
order by t.name, i.index_id,p.partition_number;

Tuttavia, questa query non funzionerà quando ci sono più file in un filegroup in quanto posso solo arrivare a mettere in relazione un'unità di allocazione con uno spazio dati e, in definitiva, un filegroup. Vorrei sapere se manca un altro DMV o catalogo che posso utilizzare per identificare ulteriormente quale file nel filegroup contiene un'unità di allocazione.

La domanda dietro questa domanda è che sto cercando di valutare gli effetti reali della compressione delle strutture partizionate. So che posso fare un uso prima e dopo FILEPROPERTY(FileName,'SpaceUsed')per il file e un prima e un dopo sys.allocation_units.used_pages/128.per ottenere queste informazioni, ma l'esercizio stesso mi ha fatto chiedermi se potevo identificare il file specifico che contiene un'unità di allocazione specifica.

Ho avuto problemi con %%physloc%%le speranze che potesse aiutare, ma non mi dà proprio quello che sto cercando. I collegamenti seguenti sono stati forniti da Aaron Bertrand :


Risposte:


11

Prova la seguente query. Crea prima una tabella temporanea locale e quindi la popola con le associazioni AllocationUnitID-to-FileID presenti in sys.dm_db_database_page_allocations, una DMF (Dynamic Management Function) non documentata introdotta in SQL Server 2012 (per le versioni precedenti al 2012, è possibile ottenere queste informazioni da DBCC IND()). Quella tabella temporanea locale viene quindi ENTRATA in una versione modificata della query originale.

I dati di quel DMF vengono inseriti in una tabella temporanea per le prestazioni poiché, a seconda delle dimensioni del database, potrebbero essere necessari più di pochi secondi per ottenere tali dati. La DISTINCTparola chiave viene utilizzata perché DMF restituisce una riga per pagina di dati e vi sono più pagine di dati per ogni unità di allocazione.

Ho unito a JOIN quei dati nella query originale poiché la query originale restituisce unità di allocazione che hanno 0 pagine di dati (in genere ROW_OVERFLOW_DATAe LOB_DATAtipi). Ho anche aggiunto il total_pagescampo in modo che sia più semplice mettere in relazione quel punto di dati con le righe che hanno NULLi file di dati. Se non ti interessano le Unità di allocazione che hanno 0 righe, allora andrebbe bene cambiarlo LEFT JOINin una INNER JOIN.

IF (OBJECT_ID(N'tempdb..#AllocationsToFiles') IS NULL)
BEGIN
    -- DROP TABLE #AllocationsToFiles;
    CREATE TABLE #AllocationsToFiles
    (
      ObjectID INT NOT NULL,
      IndexID INT NOT NULL,
      PartitionID INT NOT NULL,
      RowsetID BIGINT NOT NULL,
      AllocationUnitID BIGINT NOT NULL,
      AllocatedPageFileID SMALLINT NOT NULL
    );
END;

IF (NOT EXISTS(SELECT * FROM #AllocationsToFiles))
BEGIN
  --TRUNCATE TABLE #AllocationsToFiles;
  INSERT INTO #AllocationsToFiles (ObjectID, IndexID, PartitionID, RowsetID,
                                   AllocationUnitID, AllocatedPageFileID)
    SELECT DISTINCT alloc.[object_id], alloc.[index_id], alloc.[partition_id],
           alloc.[rowset_id], alloc.[allocation_unit_id], alloc.[allocated_page_file_id]
    FROM   sys.dm_db_database_page_allocations(DB_ID(), NULL, NULL, NULL,
                                               'LIMITED') alloc
    WHERE  alloc.is_allocated = 1
    AND    alloc.is_iam_page = 0;
END;

SELECT
    SchemaName = sh.name, 
    TableName = t.name, 
    IndexName = i.name, 
    PartitionNumber = p.partition_number,
    IndexID = i.index_id,
    IndexDataspaceID = i.data_space_id,
    AllocUnitDataspaceID = au.data_space_id,
    PartitionRows = p.[rows],
    TotalPages = au.total_pages,
    AllocationUnitType = au.type_desc,
    LogicalFileName = dbf.[name],
    PhysicalFileName = dbf.[physical_name]
    --,p.[object_id], p.[partition_id], au.allocation_unit_id
FROM sys.allocation_units au
INNER JOIN sys.partitions p
        ON au.container_id = IIF(au.[type] = 2, p.[partition_id], p.[hobt_id])
INNER JOIN sys.indexes i 
        ON i.[object_id] = p.[object_id]
       AND i.index_id = p.index_id
INNER JOIN sys.tables t 
        ON p.[object_id] = t.[object_id]
INNER JOIN sys.schemas sh
        ON t.[schema_id] = sh.[schema_id]
LEFT JOIN (#AllocationsToFiles alloc
       INNER JOIN sys.database_files dbf
               ON dbf.[file_id] = alloc.AllocatedPageFileID
          ) 
        ON alloc.ObjectID = p.[object_id]
       AND alloc.IndexID = p.index_id
       AND alloc.PartitionID = p.partition_number
       AND alloc.AllocationUnitID = au.allocation_unit_id
WHERE sh.name <> N'sys'
ORDER BY t.name, i.index_id, p.partition_number;

Questo è un ottimo strumento, grazie. Voglio sottolineare che la colonna TotalPages, è pagine totali per l'indice. Quando i risultati restituiscono più righe per indice, l'indice viene distribuito su più file, ma non mostra la quantità di indice presente su ciascun file. Ogni riga mostrerà il numero totale di pagine per indice, non per file. ( Le prime volte che l'ho eseguito pensavo che i miei indici fossero perfettamente bilanciati tra i file, mi sbagliavo )
James Jenkins

1

Remus Rusanu, il 21 maggio 2013, ha fornito una risposta a questa domanda:

Un filegroup, più file di dati, come ottenere l'elenco delle tabelle in ciascun file

La sua risposta fu:

Un oggetto in un filegroup utilizzerà tutti i file di dati nel filegroup. Qualsiasi tabella in FG1 risiede ugualmente su Datafile1, Datafile2 e Datafile3. Se è necessario controllare il posizionamento, è necessario creare filegroup distinti.


Grazie. Non voglio davvero controllare dove va, ma piuttosto vedere dove è andato.
Scorri il

3
Cordiali saluti - questo è corretto supponendo che tutti i file siano stati creati contemporaneamente. Se i file sono stati aggiunti al filegroup o sono stati utilizzati altri flag di traccia, potrebbe non essere presente in tutti i file. Non dire che ha torto, perché non lo è, dicendo che dipende :)
Sean Gallardy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.