Existe-t-il un moyen de déterminer le fichier exact qui contient une unité d'allocation dans un groupe de fichiers de plusieurs fichiers?


13

J'espérais obtenir une vue granulaire des fichiers de base de données qui contenaient quelles unités d'allocation pour les différents HoBT (alignés et non alignés) vivant dans une base de données.

La requête que j'ai toujours utilisée (voir ci-dessous) m'a bien servi jusqu'à ce que nous commencions à créer plusieurs fichiers de données par groupe de fichiers et je ne suis capable de comprendre que comment être aussi granulaire que le niveau du groupe de fichiers.

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;

Cependant, cette requête ne fonctionnera pas lorsqu'il y a plusieurs fichiers dans un groupe de fichiers car je ne peux obtenir que la relation entre une unité d'allocation et un espace de données et, finalement, un groupe de fichiers. Je voudrais savoir s'il y a un autre DMV ou catalogue qui me manque que je peux utiliser pour identifier plus en détail le fichier dans le groupe de fichiers qui contient une unité d'allocation.

La question derrière cette question est que j'essaie d'évaluer les effets réels de la compression des structures partitionnées. Je sais que je peux faire une utilisation avant et après FILEPROPERTY(FileName,'SpaceUsed')pour le fichier et un avant et après sys.allocation_units.used_pages/128.pour obtenir ces informations, mais l'exercice lui-même m'a fait me demander si je pouvais identifier le fichier spécifique qui contient une unité d'allocation spécifique.

J'ai joué avec %%physloc%%dans l'espoir que cela pourrait aider, mais cela ne m'a pas tout à fait ce que je cherche. Les liens ci-dessous ont été fournis par Aaron Bertrand :


Réponses:


11

Essayez la requête suivante. Il crée d'abord une table temporaire locale, puis la remplit avec les associations AllocationUnitID-FileID trouvées dans sys.dm_db_database_page_allocations, une fonction de gestion dynamique (DMF) non documentée introduite dans SQL Server 2012 (pour les versions antérieures à 2012, vous pouvez obtenir ces informations auprès de DBCC IND()). Cette table temporaire locale est ensuite jointe en une version modifiée de la requête d'origine.

Les données de ce DMF sont placées dans une table temporaire pour les performances car, selon la taille de la base de données, l'obtention de ces données peut prendre plus de quelques secondes. leDISTINCT mot clé est utilisé parce que DMF renvoie une ligne par page de données et qu'il existe plusieurs pages de données par unité d'allocation.

J'ai joint ces données dans la requête d'origine, car la requête d'origine renvoie des unités d'allocation qui ont 0 pages de données (généralement ROW_OVERFLOW_DATAet LOB_DATAtypes). J'ai également ajouté le total_pageschamp afin qu'il soit plus facile de relier ce point de données aux lignes qui ont des NULLs pour les fichiers de données. Si vous ne vous souciez pas des unités d'allocation qui ont 0 lignes, alors ce serait bien de changer cela LEFT JOINpour être unINNER 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;

Ceci est un excellent outil, merci. Je tiens à souligner que la colonne TotalPages, est le nombre total de pages pour l'index. Lorsque les résultats renvoient plusieurs lignes par index, l'index est réparti sur plusieurs fichiers, mais il ne montre pas la proportion de l'index sur chaque fichier. Chaque ligne affichera le nombre total de pages par index, pas par fichier. ( Les premières fois que je l'ai exécuté, j'ai pensé que les index étaient parfaitement équilibrés entre les fichiers, j'avais tort )
James Jenkins

1

Remus Rusanu, le 21 mai 2013, a répondu à cette question:

Un groupe de fichiers, plusieurs fichiers de données, comment obtenir la liste des tables dans chaque fichier

Sa réponse a été:

Un objet dans un groupe de fichiers utilisera tous les fichiers de données du groupe de fichiers. Toute table dans FG1 réside également sur Datafile1, Datafile2 et Datafile3. Si vous devez contrôler le placement, vous devez créer des groupes de fichiers distincts.


Merci. Je ne veux pas vraiment contrôler où ça va, mais plutôt voir où ça va.
swasheck

3
FYI - c'est correct en supposant que tous les fichiers ont été créés en même temps. Si des fichiers ont été ajoutés au groupe de fichiers ou si d'autres indicateurs de trace ont été utilisés, il se peut qu'ils ne figurent pas dans tous les fichiers. Ne pas dire qu'il a tort, parce qu'il ne l'est pas, dire que ça dépend :)
Sean Gallardy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.