Существует ли способ определить точный файл, который содержит единицу выделения в файловой группе из нескольких файлов?

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%%надеждой, что это может помочь, но это не совсем дает мне то, что я ищу. Ссылки ниже предоставлены Аароном Бертраном :

swasheck
источник

Ответы:

11

Попробуйте следующий запрос. Сначала он создает локальную временную таблицу, а затем заполняет ее ассоциациями AllocationUnitID-to-FileID, найденными вsys.dm_db_database_page_allocations недокументированной динамической функции управления (DMF), введенной в SQL Server 2012 (для версий до 2012 г. эту информацию можно получить из DBCC IND()). Эта локальная временная таблица затем присоединяется к измененной версии исходного запроса.

Данные из этого DMF помещаются во временную таблицу для повышения производительности, поскольку, в зависимости от размера базы данных, получение этих данных может занять более нескольких секунд. DISTINCTИспользуется ключевое слово , потому что ДМФ возвращает одну строку для каждой страницы данных, и существует множество страниц данных в каждой единице выделения.

Я оставил эти данные в исходном запросе, так как исходный запрос возвращает единицы размещения, которые имеют 0 страниц данных (обычно ROW_OVERFLOW_DATAи LOB_DATAтипов). Я также добавил это total_pagesполе, чтобы было проще связать эту точку данных со строками, имеющимися NULLдля файлов данных. Если вам не нужны единицы размещения, имеющие 0 строк, было бы неплохо изменить это LEFT JOINзначение на 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;
Соломон Руцкий
источник
Это отличный инструмент, спасибо. Я хочу отметить, что столбец TotalPages - это общее количество страниц для индекса. Когда результаты возвращают несколько строк на индекс, индекс распределяется по нескольким файлам, но он не показывает, сколько индекса находится в каждом файле. В каждой строке будет показано общее количество страниц в индексе, а не в файле. ( Первые несколько раз, когда я запускал его, я думал, что мои индексы прекрасно сбалансированы по файлам, я ошибался )
Джеймс Дженкинс
1

Ремус Русану 21 мая 2013 года дал ответ на этот вопрос:

Одна файловая группа, несколько файлов данных, как получить список таблиц в каждом файле

Его ответ был:

Объект в файловой группе будет использовать все файлы данных в файловой группе. Любая таблица в FG1 в равной степени находится в Datafile1, Datafile2 и Datafile3. Если вам нужно контролировать размещение, вам нужно создать отдельные файловые группы.

ДКП
источник
Благодарю. Я на самом деле не хочу контролировать, куда это идет, а лучше посмотреть, куда это уходит.
swasheck
3
К вашему сведению - это правильно, если все файлы были созданы одновременно. Если файлы были добавлены в файловую группу или использовались другие флаги трассировки, это может быть не во всех файлах. Не говорю, что он не прав, потому что он не говорит, что это зависит :)
Шон Галларди