是否存在确定多个文件文件组中包含分配单元的确切文件的方法?


13

我希望能够详细了解哪些数据库文件包含用于数据库中各种HoBT(对齐和不对齐)的分配单元。

在我们开始为每个文件组创建多个数据文件之前,我一直使用的查询(请参见下文)对我很有帮助,而我只能弄清楚如何获得与文件组级别一样的粒度。

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;

但是,当文件组中有多个文件时,此查询将不起作用,因为我只能将分配单元与数据空间,最终与文件组相关联。我想知道是否还有其他我缺少的DMV或目录,可以用来进一步确定文件组中的哪个文件包含分配单元。

这个问题背后的问题是,我正在尝试评估压缩分区结构的实际效果。我知道我可以FILEPROPERTY(FileName,'SpaceUsed')对文件进行前后使用,也可以前后sys.allocation_units.used_pages/128.进行获取信息,但是练习本身使我想知道是否可以标识包含特定分配单元的特定文件。

我一直在四处%%physloc%%寻找希望它能有所帮助的东西,但并不能完全满足我的需求。以下链接由亚伦·伯特兰Aaron Bertrand)提供:


Answers:


11

请尝试以下查询。它首先创建一个本地临时表,然后使用sys.dm_db_database_page_allocations在SQL Server 2012中引入的未记录的动态管理功能(DMF)中的AllocationUnitID到FileID关联填充该表(对于2012之前的版本,您可以从获取此信息DBCC IND())。然后将该本地临时表加入原始查询的修改版本中。

来自该DMF的数据被放入临时表中以提高性能,因为根据数据库的大小,获取该数据可能要花费几秒钟的时间。使用该DISTINCT关键字是因为DMF每个数据页返回一行,并且每个分配单元有多个数据页。

我将这些数据左联接到原始查询中,因为原始查询返回的分配单元具有0个数据页(通常ROW_OVERFLOW_DATALOB_DATA类型)。我还添加了该total_pages字段,以便将数据点与具有NULL数据文件的行关联起来更加容易。如果您不关心具有0行的分配单位,则可以将其更改LEFT JOININNER 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;

这是一个很棒的工具,谢谢。我确实要指出,TotalPages列是索引的总页数。当结果为每个索引返回多行时,该索引分布在多个文件中,但没有显示每个文件上有多少索引。每行将显示每个索引而不是每个文件的总页数。(我运行它的前几次,我认为,很酷,我的索引在各个文件之间是完美平衡的,我错了
James Jenkins

1

Remus Rusanu在2013年5月21日提供了以下问题的答案:

一个文件组,多个数据文件,如何获取每个文件中的表列表

他的回答是:

文件组中的对象将使用该文件组中的所有数据文件。FG1中的任何表均等地位于Datafile1,Datafile2和Datafile3上。如果需要控制放置,则需要创建不同的文件组。


谢谢。我并不是很想控制它的去向,而是想知道它的去向。
swasheck '16

3
仅供参考-假设所有文件都是同时创建的,这是正确的。如果将文件添加到文件组或使用了其他跟踪标志,则可能不是所有文件中都有。不是说他错了,因为他没有错,这要取决于 :)
肖恩·加拉迪
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.