【问题标题】:SQL Server: how can I get the correct DB size from sys.master_files?SQL Server:如何从 sys.master_files 获得正确的数据库大小?
【发布时间】:2019-04-03 17:26:22
【问题描述】:

我正在处理一个收集与数据库还原相关的一些信息的查询,但我无法获得正确的数据库大小。以下查询为我提供了数据库名称、上次还原日期、数据库大小和上次还原它的人的用户名。

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 所示。我怎样才能做到这一点?

【问题讨论】:

    标签: sql-server group-by type-conversion aggregate


    【解决方案1】:

    如果您只是想转换大小列以匹配属性中的值,您只需将页面转换为 MB - 因此乘以 8 得到 KB,然后除以 1024 得到 MB。

    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
    

    这里的 Size 值可能比您在属性中看到的更准确,因为 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
    

    【讨论】:

    • 感谢您的帮助,这正是我所需要的,而且很有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    相关资源
    最近更新 更多