SQL Server: как я могу получить правильный размер БД из sys.master_files? - PullRequest
1 голос
/ 03 апреля 2019

Я работаю над запросом, который собирает некоторую информацию, связанную с восстановлением БД, и у меня возникают проблемы с получением правильного размера БД. Следующий запрос предоставляет мне имя БД, дату последнего восстановления, размер БД и имя пользователя последнего человека, который его восстановил.

WITH lastrestores AS
(
    SELECT 
        DatabaseName = [d].[name], 
        [r].[restore_date], 
        [f].[size], 
        [r].[user_name], 
        RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME ORDER BY r.[restore_date] DESC) 
    FROM   
        master.sys.databases d 
    LEFT OUTER JOIN 
        msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME 
    LEFT JOIN 
        master.sys.master_files f ON d.database_id = f.database_id
) 
SELECT * 
FROM [lastrestores] 
WHERE [rownum] = 1 
  AND databasename LIKE 'stuff%' 
ORDER BY restore_date DESC

Однако это не показывает правильный размер БД. Когда я проверяю размеры в .mdf файле и свойствах базы данных, он показывает меньший размер, чем этот запрос возвращает. Когда я проверяю хранимую процедуру sp_databases, она показывает, что это делается для размера БД:

DATABASE_SIZE = CONVERT(INT,
                        CASE   -- more than 2TB(maxint) worth of pages (by 8K each) can not fit an int...
                           WHEN SUM(CONVERT(BIGINT, s_mf.size)) >= 268435456
                              THEN NULL
                              ELSE SUM(CONVERT(BIGINT, s_mf.size)) * 8 -- Convert from 8192 byte pages to Kb
                        END)

Я попытался включить этот раздел в исходный запрос, но натолкнулся на ошибку «не содержится в статистической функции или группе по»:

WITH lastrestores AS
(
    SELECT 
        DatabaseName = [d].[name], 
        [r].[restore_date], 
        CONVERT(INT,
                CASE
                   WHEN SUM(CONVERT(BIGINT, [f].[size])) >= 268435456
                      THEN NULL
                      ELSE SUM(CONVERT(BIGINT, [f].[size])) * 8
                END) AS DBSize, 
                [r].[user_name], 
        RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME ORDER BY r.[restore_date] DESC) 
    FROM   
        master.sys.databases d 
    LEFT OUTER JOIN 
        msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME 
    LEFT JOIN 
        master.sys.master_files f ON d.database_id = f.database_id
) 
SELECT * 
FROM [lastrestores] 
WHERE [rownum] = 1 
  AND databasename LIKE 'stuff%' 
ORDER BY restore_date DESC 

Хотя я и понимаю основы этой ошибки, я не совсем уверен, как ее исправить, чтобы получить то, что мне нужно, поскольку этот запрос становится более сложным, чем я привык. Моим идеальным результатом будет исходный запрос, который я разместил сверху, но с правильными размерами БД, как показано в sp_databases. Как мне этого добиться?

1 Ответ

2 голосов
/ 04 апреля 2019

Если вы просто хотите преобразовать столбец размера в соответствии со значениями в свойствах, вам просто нужно преобразовать страницы в МБ - умножьте на 8, чтобы получить КБ, а затем разделите на 1024, чтобы получить МБ.

WITH lastrestores AS
(
    SELECT 
        DatabaseName = [d].[name], 
        [r].[restore_date], 
        [size] = CAST([f].[size] * 8 / 1024.0 AS DECIMAL(10,2)) , 
        [r].[user_name], 
        RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME ORDER BY r.[restore_date] DESC) 
    FROM   
        master.sys.databases d 
    LEFT OUTER JOIN 
        msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME 
    LEFT JOIN 
        master.sys.master_files f ON d.database_id = f.database_id
) 
SELECT * 
FROM [lastrestores] 
WHERE [rownum] = 1 
ORDER BY restore_date DESC

Это значение размера здесь может быть немного более точным, чем то, что вы видите в свойствах, потому что SSMS округляется.

Меня беспокоит, что если у вас более одного файла данных, этоне будет точно отображать размер журнала вашей базы данных без журнала.

Я бы, вероятно, сделал что-то подобное, чтобы включить все файлы данных.

SELECT 
    DatabaseName = DB_NAME(f.database_id)
    ,r.restore_date
    ,CAST(SUM(f.size * 8 / 1024.0) AS DECIMAL(10,2))
    ,r.user_name
FROM sys.master_files f
OUTER APPLY 
    (SELECT TOP 1 * FROM msdb.dbo.[restorehistory] r WHERE r.[destination_database_name] = DB_NAME(f.database_id) ORDER BY restore_date desc) r 
WHERE f.type = 0
GROUP BY f.database_id, r.restore_date, r.user_name
ORDER BY r.restore_date desc
...