【问题标题】:SQL Server 2008: How to query all databases sizes?SQL Server 2008:如何查询所有数据库大小?
【发布时间】:2011-08-22 04:02:24
【问题描述】:

我有 MS SQL 2008 R2,500 个数据库。 查询所有数据库大小的最有效、最简单和“现代”的方法是什么。

输出应该有列:

  • 数据库名称
  • 数据文件大小
  • 日志文件大小

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008-r2


    【解决方案1】:
    with fs
    as
    (
        select database_id, type, size * 8.0 / 1024 size
        from sys.master_files
    )
    select 
        name,
        (select sum(size) from fs where type = 0 and fs.database_id = db.database_id) DataFileSizeMB,
        (select sum(size) from fs where type = 1 and fs.database_id = db.database_id) LogFileSizeMB
    from sys.databases db
    

    【讨论】:

    • @Derek Smith - 大小列以页为单位。一页的大小是 8kB,因此公式 SizeInMb = PagesCount * 8 / 1024。我一直认为 1MB = 1024kB。我认为即使是微软也没有足够的力量来改变这一点:)。
    • 这个答案由于某种原因在我们的系统上报告了错误的 tempdb 值。请参阅this related question
    【解决方案2】:

    我不知道你所说的效率到底是什么意思,但这很简单,对我有用:

    SELECT
        DB_NAME(db.database_id) DatabaseName,
        (CAST(mfrows.RowSize AS FLOAT)*8)/1024 RowSizeMB,
        (CAST(mflog.LogSize AS FLOAT)*8)/1024 LogSizeMB,
        (CAST(mfstream.StreamSize AS FLOAT)*8)/1024 StreamSizeMB,
        (CAST(mftext.TextIndexSize AS FLOAT)*8)/1024 TextIndexSizeMB
    FROM sys.databases db
        LEFT JOIN (SELECT database_id, SUM(size) RowSize FROM sys.master_files WHERE type = 0 GROUP BY database_id, type) mfrows ON mfrows.database_id = db.database_id
        LEFT JOIN (SELECT database_id, SUM(size) LogSize FROM sys.master_files WHERE type = 1 GROUP BY database_id, type) mflog ON mflog.database_id = db.database_id
        LEFT JOIN (SELECT database_id, SUM(size) StreamSize FROM sys.master_files WHERE type = 2 GROUP BY database_id, type) mfstream ON mfstream.database_id = db.database_id
        LEFT JOIN (SELECT database_id, SUM(size) TextIndexSize FROM sys.master_files WHERE type = 4 GROUP BY database_id, type) mftext ON mftext.database_id = db.database_id
    

    结果如下:

    DatabaseName  RowSizeMB LogSizeMB StreamSizeMB TextIndexSizeMB
    ------------- --------- --------- ------------ ---------------
    master        4         1.25      NULL         NULL
    model         2.25      0.75      NULL         NULL
    msdb          14.75     8.1875    NULL         NULL
    tempdb        8         0.5       NULL         NULL
    

    注意:灵感来自this article

    【讨论】:

    • 我使用这个在每一列上都得到 NULL 值?知道为什么吗?
    • 如果 sys.master_files 为空,则可能是权限。最小权限是 CREATE DATABASE、ALTER ANY DATABASE 或 VIEW ANY DEFINITION(参考:BOL sys.master_files)
    【解决方案3】:

    这是一个简单、快速且可靠的查询,它将以漂亮、易于阅读的输出提供所有数据库和日志文件的名称、大小以及数据库状态(例如 ONLINE):

    SELECT
        D.name,
        F.Name AS FileType,
        F.physical_name AS PhysicalFile,
        F.state_desc AS OnlineStatus,
        CAST(F.size AS bigint) * 8*1024 AS SizeInBytes,
        CAST((F.size*8.0)/1024/1024 AS decimal(18,3)) AS SizeInGB
    FROM 
        sys.master_files F
        INNER JOIN sys.databases D ON D.database_id = F.database_id
    ORDER BY SizeInBytes desc
    

    【讨论】:

      【解决方案4】:

      按数据库总大小排序 Desc

      SELECT     
      DB_NAME(db.database_id) DatabaseName,     
      (CAST(mfrows.RowSize AS FLOAT)*8)/1024 RowSizeMB,     
      (CAST(mflog.LogSize AS FLOAT)*8)/1024 LogSizeMB, 
      (CAST(mfrows.RowSize AS FLOAT)*8)/1024/1024+(CAST(mflog.LogSize AS FLOAT)*8)/1024/1024 DBSizeG,
      (CAST(mfstream.StreamSize AS FLOAT)*8)/1024 StreamSizeMB,     
      (CAST(mftext.TextIndexSize AS FLOAT)*8)/1024 TextIndexSizeMB 
      FROM sys.databases db     
      LEFT JOIN (SELECT database_id, 
                        SUM(size) RowSize 
                  FROM sys.master_files 
                  WHERE type = 0 
                  GROUP BY database_id, type) mfrows 
          ON mfrows.database_id = db.database_id     
      LEFT JOIN (SELECT database_id, 
                        SUM(size) LogSize 
                  FROM sys.master_files 
                  WHERE type = 1 
                  GROUP BY database_id, type) mflog 
          ON mflog.database_id = db.database_id     
      LEFT JOIN (SELECT database_id, 
                        SUM(size) StreamSize 
                        FROM sys.master_files 
                        WHERE type = 2 
                        GROUP BY database_id, type) mfstream 
          ON mfstream.database_id = db.database_id     
      LEFT JOIN (SELECT database_id, 
                        SUM(size) TextIndexSize 
                        FROM sys.master_files 
                        WHERE type = 4 
                        GROUP BY database_id, type) mftext 
          ON mftext.database_id = db.database_id 
             ORDER BY 4 DESC
      

      【讨论】:

        【解决方案5】:

        一切似乎都过于复杂!还是我错过了什么?

        当然,您只需要这样的东西:

        select d.name, case when m.type = 0 then 'Data' else 'Log' end,  m.size * 8 / 1024
        from sys.master_files m JOIN sys.databases d ON d.database_id = m.database_id
        

        或者如果你不想要日志:

        select d.name, m.size * 8 / 1024
        from sys.master_files m JOIN sys.databases d ON d.database_id = m.database_id and m.type =0
        

        【讨论】:

          【解决方案6】:
          SELECT
              DB.name,
              SUM(CASE WHEN type = 0 THEN MF.size * 8 / 1024 ELSE 0 END) AS DataFileSizeMB,
              SUM(CASE WHEN type = 1 THEN MF.size * 8 / 1024 ELSE 0 END) AS LogFileSizeMB
          FROM
              sys.master_files MF
              JOIN sys.databases DB ON DB.database_id = MF.database_id
          GROUP BY DB.name
          ORDER BY DataFileSizeMB DESC
          

          【讨论】:

          • GROUP BY DB.name, DB.database_id ORDER BY DB.database_id 保留表格顺序。
          【解决方案7】:

          请查找更多详细信息或从以下链接下载脚本 https://gallery.technet.microsoft.com/SIZE-OF-ALL-DATABASES-IN-0337f6d5#content

           DECLARE @spacetable table
           (
           database_name varchar(50) ,
           total_size_data int,
           space_util_data int,
           space_data_left int,
           percent_fill_data float,
           total_size_data_log int,
           space_util_log int,
           space_log_left int,
           percent_fill_log char(50),
           [total db size] int,
           [total size used] int,
           [total size left] int
           )
           insert into  @spacetable
           EXECUTE master.sys.sp_MSforeachdb 'USE [?];
           select x.[DATABASE NAME],x.[total size data],x.[space util],x.[total size data]-x.[space util] [space left data],
           x.[percent fill],y.[total size log],y.[space util],
           y.[total size log]-y.[space util] [space left log],y.[percent fill],
           y.[total size log]+x.[total size data] ''total db size''
           ,x.[space util]+y.[space util] ''total size used'',
           (y.[total size log]+x.[total size data])-(y.[space util]+x.[space util]) ''total size left''
            from (select DB_NAME() ''DATABASE NAME'',
           sum(size*8/1024) ''total size data'',sum(FILEPROPERTY(name,''SpaceUsed'')*8/1024) ''space util''
           ,case when sum(size*8/1024)=0 then ''less than 1% used'' else
           substring(cast((sum(FILEPROPERTY(name,''SpaceUsed''))*1.0*100/sum(size)) as CHAR(50)),1,6) end ''percent fill''
           from sys.master_files where database_id=DB_ID(DB_NAME())  and  type=0
           group by type_desc  ) as x ,
           (select 
           sum(size*8/1024) ''total size log'',sum(FILEPROPERTY(name,''SpaceUsed'')*8/1024) ''space util''
           ,case when sum(size*8/1024)=0 then ''less than 1% used'' else
           substring(cast((sum(FILEPROPERTY(name,''SpaceUsed''))*1.0*100/sum(size)) as CHAR(50)),1,6) end ''percent fill''
           from sys.master_files where database_id=DB_ID(DB_NAME())  and  type=1
           group by type_desc  )y'
           select * from @spacetable
           order by database_name
          

          【讨论】:

            【解决方案8】:

            我最近看到这个页面正在寻找类似的东西。 万一有人遇到这种情况并且只对核心用户数据库感兴趣,您可以使用类似这样的东西,不包括 Master、msdb...

            SELECT
            DB_NAME(db.database_id) DatabaseName,
            (CAST(mfrows.RowSize AS FLOAT)*8)/1024 RowSizeMB,
            (CAST(mflog.LogSize AS FLOAT)*8)/1024 LogSizeMB
            FROM sys.databases db
            LEFT JOIN (SELECT database_id, SUM(size) RowSize FROM sys.master_files WHERE type = 0 GROUP BY database_id, type) mfrows ON mfrows.database_id = db.database_id
            LEFT JOIN (SELECT database_id, SUM(size) LogSize FROM sys.master_files WHERE type = 1 GROUP BY database_id, type) mflog ON mflog.database_id = db.database_id
            where DB_NAME(db.database_id) not like 'master'
            and DB_NAME(db.database_id) not like 'msdb'
            and DB_NAME(db.database_id) not like 'model'
            and DB_NAME(db.database_id) not like 'tempdb'
            and DB_NAME(db.database_id) not like 'Northwind'
            and DB_NAME(db.database_id) not like 'ReportServer'
            order by DB_NAME(db.database_id)
            

            【讨论】:

              【解决方案9】:
              IF OBJECT_ID('tempdb.dbo.#space') IS NOT NULL
                  DROP TABLE #space
              
              CREATE TABLE #space (
                    database_id INT PRIMARY KEY
                  , data_used_size DECIMAL(18,2)
                  , log_used_size DECIMAL(18,2)
              )
              
              DECLARE @SQL NVARCHAR(MAX)
              
              SELECT @SQL = STUFF((
                  SELECT '
                  USE [' + d.name + ']
                  INSERT INTO #space (database_id, data_used_size, log_used_size)
                  SELECT
                        DB_ID()
                      , SUM(CASE WHEN [type] = 0 THEN space_used END)
                      , SUM(CASE WHEN [type] = 1 THEN space_used END)
                  FROM (
                      SELECT s.[type], space_used = SUM(FILEPROPERTY(s.name, ''SpaceUsed'') * 8. / 1024)
                      FROM sys.database_files s
                      GROUP BY s.[type]
                  ) t;'
                  FROM sys.databases d
                  WHERE d.[state] = 0
                  FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
              
              EXEC sys.sp_executesql @SQL
              
              SELECT
                    d.database_id
                  , d.name
                  , d.state_desc
                  , d.recovery_model_desc
                  , t.total_size
                  , t.data_size
                  , s.data_used_size
                  , t.log_size
                  , s.log_used_size
              FROM (
                  SELECT
                        database_id
                      , log_size = CAST(SUM(CASE WHEN [type] = 1 THEN size END) * 8. / 1024 AS DECIMAL(18,2))
                      , data_size = CAST(SUM(CASE WHEN [type] = 0 THEN size END) * 8. / 1024 AS DECIMAL(18,2))
                      , total_size = CAST(SUM(size) * 8. / 1024 AS DECIMAL(18,2))
                  FROM sys.master_files
                  GROUP BY database_id
              ) t
              JOIN sys.databases d ON d.database_id = t.database_id
              LEFT JOIN #space s ON d.database_id = s.database_id
              ORDER BY t.total_size DESC
              

              【讨论】:

                【解决方案10】:

                不要窃取你的答案并将其调整为分数或任何东西,但这是另一个分解:

                select d.name, 
                    sum(m0.size*8.0/1024) data_file_size_mb, 
                    sum(m1.size*8.0/1024) log_file_size_mb 
                from sys.databases d
                inner join sys.master_files m0 on m0.database_id = d.database_id
                inner join sys.master_files m1 on m1.database_id = d.database_id
                where m0.type = 0 and m1.type = 1
                group by d.name, d.database_id
                order by d.database_id
                

                【讨论】:

                • Mihai Bejenariu 的 答案更接近我在这里的尝试。
                【解决方案11】:

                简化和改进版:

                SELECT
                    D.name,
                    CAST(SUM(F.size) AS bigint) * 8*1024 AS SizeInBytes,
                    CAST(SUM(F.size*8.0)/1024/1024 AS decimal(18,3)) AS SizeInGB
                FROM 
                    sys.master_files F
                    INNER JOIN sys.databases D ON D.database_id = F.database_id
                GROUP BY D.name
                ORDER BY SizeInBytes desc
                

                【讨论】:

                  【解决方案12】:

                  更好更简单的一个

                  SELECT [Database Name] = DB_NAME(database_id),
                       [Type] = CASE WHEN Type_Desc = 'ROWS' THEN 'Data File(s)'
                                 WHEN Type_Desc = 'LOG'  THEN 'Log File(s)'
                                 ELSE Type_Desc END,
                       [Size in MB] = CAST( ((SUM(Size)* 8) / 1024.0) AS DECIMAL(18,2) )
                  FROM   sys.master_files
                  --Uncomment if you need to query for a particular database
                  --WHERE      database_id = DB_ID(‘Database Name’) 
                  GROUP BY  GROUPING SETS
                          (
                                 (DB_NAME(database_id), Type_Desc),
                                 (DB_NAME(database_id))
                          ) ORDER BY      DB_NAME(database_id), Type_Desc DESC
                  

                  它将分别为您提供数据文件和日志文件的大小,如下所示

                  DatabaseName    Type            Size in MB
                  -------------------------------------------
                  FMS             Data File(s)    23.00
                  FMS             Log File(s)     1.50
                  PointOfSale     Data File(s)    4.00
                  PointOfSale     Log File(s)     1.25
                  Union2          Data File(s)    336.00
                  Union2          Log File(s)     1191.13
                  SurveyProject   Data File(s)    4.00
                  SurveyProject   Log File(s)     1.00
                  

                  【讨论】:

                  • 这不是两个分组集的输出。
                  【解决方案13】:

                  以下代码非常适合我。

                      SELECT
                          D.name As DbName,
                          F.Name AS FullDbName,
                          CASE WHEN F.type_desc='ROWS' THEN 'mdf' ELSE 'ldf' END AS FileType,
                          F.physical_name AS PhysicalFile,
                          CONVERT(DATE,D.create_date) AS CreationDate,
                          F.state_desc AS OnlineStatus,
                          CAST((F.size*8)/1024 AS VARCHAR(26)) + ' MB' AS FileSize_MB,
                          CAST(F.size*8 AS VARCHAR(32)) + ' Bytes' AS FileSize_Bytes,
                          CAST(CAST(ROUND((F.size*8)/(1024.0*1024.0),0) AS INT) AS VARCHAR(32)) + ' GB' AS FileSize_GB
                  
                      FROM 
                          sys.master_files F
                          INNER JOIN sys.databases D ON D.database_id = F.database_id
                  
                      ORDER BY
                           D.name 
                  

                  【讨论】:

                    【解决方案14】:

                    所有这些示例在我的大多数数据库服务器上都可以正常工作。 但是,如果您有 1 台具有多个实例的服务器,并且所有这些服务器都不会给您任何结果。

                    例如,第一个查询给出的结果如下:

                    name    DataFileSizeMB  LogFileSizeMB
                    master  NULL    NULL
                    tempdb  NULL    NULL
                    model   NULL    NULL
                    msdb    NULL    NULL
                    

                    所以数据库是从sys.databases 中选择的,但是表sys.master_files 似乎是空的或没有给出结果。

                    即使是像select * from sys.master_files 这样的简单查询也有 0 条记录的结果。 您没有收到任何错误,但没有找到记录。 在我只有 1 个数据库实例的服务器上,这可以正常工作。

                    【讨论】:

                    【解决方案15】:

                    有时 SECURITY 问题会阻止询问所有 db,您需要使用 db 前缀逐个查询,对于这些情况,我创建了此动态查询

                    go
                    declare @Results table ([Name] nvarchar(max), [DataFileSizeMB] int, [LogFileSizeMB] int);
                    
                    declare @QaQuery nvarchar(max)
                    declare @name nvarchar(max)
                    
                    declare MY_CURSOR cursor 
                      local static read_only forward_only
                    for 
                    select name from master.dbo.sysdatabases where name not in ('master', 'tempdb', 'model', 'msdb', 'rdsadmin');
                    
                    open MY_CURSOR
                    fetch next from MY_CURSOR into @name
                    while @@FETCH_STATUS = 0
                    begin 
                        if(len(@name)>0)
                        begin
                            print @name + ' Column Exist'
                            set @QaQuery = N'select 
                                                '''+@name+''' as Name
                                                ,sum(case when type = 0 then size else 0 end) as DataFileSizeMB
                                                ,sum(case when type = 1 then size else 0 end) as LogFileSizeMB
                                            from ['+@name+'].sys.database_files
                                            group by replace(name, ''_log'', '''')';
                    
                            insert @Results exec sp_executesql @QaQuery;
                        end
                      fetch next from MY_CURSOR into @name
                    end
                    close MY_CURSOR
                    deallocate MY_CURSOR
                    
                    select * from @Results order by DataFileSizeMB desc
                    go
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多