【问题标题】:Listing information about all database files in SQL Server列出有关 SQL Server 中所有数据库文件的信息
【发布时间】:2023-03-19 13:23:02
【问题描述】:

是否可以列出有关 SQL Server 上所有数据库的文件 (MDF/LDF) 的信息?

我想获得一个列表,显示哪个数据库正在使用本地磁盘上的哪些文件。

我尝试了什么:

  • exec sp_databases所有数据库
  • select * from sys.databases 显示了有关每个数据库的大量信息 - 但不幸的是,它没有显示每个数据库使用的文件。
  • select * from sys.database_files 显示 master 数据库的 mdf/ldf 文件 - 但不显示其他数据库

【问题讨论】:

    标签: sql-server sql-server-2008 tsql database-management


    【解决方案1】:

    您可以使用sys.master_files

    包含存储在主数据库中的每个文件的行 数据库。这是一个单一的系统范围视图。

    【讨论】:

    • 谢谢,那(与 sys.databases 一起)正是我想要的!
    • 从 sys.master_files 中选择 *
    • @M4N 如果您只想获取数据库名称,也可以调用DB_NAME(database_id) 而不是加入sys.databases
    【解决方案2】:

    如果您想获取数据库的位置,您可以查看Get All DBs Location
    您可以使用sys.master_files 获取数据库的位置,使用sys.database 获取数据库名称

    SELECT
        db.name AS DBName,
        type_desc AS FileType,
        Physical_Name AS Location
    FROM
        sys.master_files mf
    INNER JOIN 
        sys.databases db ON db.database_id = mf.database_id
    

    【讨论】:

      【解决方案3】:

      我正在使用脚本来获取每个文件中的空白空间:

      Create Table ##temp
      (
          DatabaseName sysname,
          Name sysname,
          physical_name nvarchar(500),
          size decimal (18,2),
          FreeSpace decimal (18,2)
      )   
      Exec sp_msforeachdb '
      Use [?];
      Insert Into ##temp (DatabaseName, Name, physical_name, Size, FreeSpace)
          Select DB_NAME() AS [DatabaseName], Name,  physical_name,
          Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2) as decimal(18,2)) as nvarchar) Size,
          Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2) as decimal(18,2)) -
              Cast(FILEPROPERTY(name, ''SpaceUsed'') * 8.0/1024.0 as decimal(18,2)) as nvarchar) As FreeSpace
          From sys.database_files
      '
      Select * From ##temp
      drop table ##temp
      

      大小以 KB 表示。

      【讨论】:

      • Use [?] 应该做什么?它给出了一个错误,它无法找到该存储过程。删除它只会多次显示系统数据库。
      【解决方案4】:

      我创建了这个查询:

      SELECT 
          db.name AS                                   [Database Name], 
          mf.name AS                                   [Logical Name], 
          mf.type_desc AS                              [File Type], 
          mf.physical_name AS                          [Path], 
          CAST(
              (mf.Size * 8
              ) / 1024.0 AS DECIMAL(18, 1)) AS         [Initial Size (MB)], 
          'By '+IIF(
                  mf.is_percent_growth = 1, CAST(mf.growth AS VARCHAR(10))+'%', CONVERT(VARCHAR(30), CAST(
              (mf.growth * 8
              ) / 1024.0 AS DECIMAL(18, 1)))+' MB') AS [Autogrowth], 
          IIF(mf.max_size = 0, 'No growth is allowed', IIF(mf.max_size = -1, 'Unlimited', CAST(
              (
                      CAST(mf.max_size AS BIGINT) * 8
              ) / 1024 AS VARCHAR(30))+' MB')) AS      [MaximumSize]
      FROM 
           sys.master_files AS mf
           INNER JOIN sys.databases AS db ON
                  db.database_id = mf.database_id
      

      【讨论】:

        【解决方案5】:

        你也可以试试这个。

         select db_name(dbid) dbname, filename from sys.sysaltfiles
        

        【讨论】:

          【解决方案6】:

          执行下面的sql(只有当你没有多个mdf/ldf文件用于同一个数据库时才有效)

          SELECT
              db.name AS DBName,
              (select mf.Physical_Name FROM sys.master_files mf where mf.type_desc = 'ROWS' and db.database_id = mf.database_id ) as DataFile,
              (select mf.Physical_Name FROM sys.master_files mf where mf.type_desc = 'LOG' and db.database_id = mf.database_id ) as LogFile
          FROM sys.databases db
          

          将返回此输出

          DBName       DataFile                     LogFile
          --------------------------------------------------------------------------------
          master       C:\....\master.mdf           C:\....\mastlog.ldf
          tempdb       C:\....\tempdb.mdf           C:\....\templog.ldf
          model        C:\....\model.mdf            C:\....\modellog.ldf
          

          和其他数据库

          如果您的 TempDB 有多个 MDF(就像我的一样),此脚本将失败。 但是,您可以使用

          WHERE db.database_id > 4
          

          最后会返回除系统数据库以外的所有数据库。

          【讨论】:

          • 我意识到这是一个小数据集,但这不是使用相关子查询的理由。它们在 Oracle 上可能很好,但它们在 SQL Server 上是严重的性能杀手,因为它们会导致逐行处理。您的脚本将为 sys.databases 表中的每一行查询 sys.master_files 表两次。
          • 除了 Davos 的评论...如果您有多个数据文件或任何数据库的日志文件,此脚本也会失败并出现错误。 (例如,子查询返回超过 1 个值。)
          • @Davos 我知道你在说什么,但这取决于你执行此查询的频率,否则它可能是你不需要的预优化。
          • 我普遍同意早期优化是不好的,但我要说的是相关子查询只是一种糟糕的模式,一开始就不应该使用。 “从不”规则总是有例外,但这不是其中一种情况。我知道这是次要的,在这里可能真的无关紧要,但这不是重点。这是一个供新手学习良好实践的公共论坛,因此您需要提供榜样代码。
          • 如果其中一个数据库使用了多个数据文件,查询会出错。这是使用联接的查询版本。干杯! SELECT db.name AS DBName, db.database_id, mfr.Physical_Name AS DataFile, mfl.Physical_Name AS LogFile FROM sys.databases db JOIN sys.master_files mfr ON db.database_id=mfr.database_id AND mfr.type_desc='ROWS' JOIN sys .master_files mfl ON db.database_id=mfl.database_id AND mfl.type_desc='LOG' ORDER BY db.database_id
          【解决方案7】:

          使用此脚本,您可以显示所有使用的数据库名称和文件(系统数据库除外)。

          select name,physical_name from sys.master_files where database_id > 4
          

          【讨论】:

            【解决方案8】:

            以下脚本可用于获取以下信息: 1. 数据库大小信息 2. 文件空间信息 3. 自动增长 4. 恢复模式 5. log_reuse_backup信息

            CREATE TABLE #tempFileInformation
            (
            DBNAME          NVARCHAR(256),
            [FILENAME]      NVARCHAR(256),
            [TYPE]          NVARCHAR(120),
            FILEGROUPNAME   NVARCHAR(120),
            FILE_LOCATION   NVARCHAR(500),
            FILESIZE_MB     DECIMAL(10,2),
            USEDSPACE_MB    DECIMAL(10,2),
            FREESPACE_MB    DECIMAL(10,2),
            AUTOGROW_STATUS NVARCHAR(100)
            )
            GO
            
            DECLARE @SQL VARCHAR(2000)
            
            SELECT @SQL = '
             USE [?]
                        INSERT INTO #tempFileInformation
                        SELECT  
                            DBNAME          =DB_NAME(),     
                            [FILENAME]      =A.NAME,
                            [TYPE]          = A.TYPE_DESC,
                            FILEGROUPNAME   = fg.name,
                            FILE_LOCATION   =a.PHYSICAL_NAME,
                            FILESIZE_MB     = CONVERT(DECIMAL(10,2),A.SIZE/128.0),
                            USEDSPACE_MB    = CONVERT(DECIMAL(10,2),(A.SIZE/128.0 - ((A.SIZE - CAST(FILEPROPERTY(A.NAME,''SPACEUSED'') AS INT))/128.0))),
                            FREESPACE_MB    = CONVERT(DECIMAL(10,2),(A.SIZE/128.0 -  CAST(FILEPROPERTY(A.NAME,''SPACEUSED'') AS INT)/128.0)),
                            AUTOGROW_STATUS = ''BY '' +CASE is_percent_growth when 0 then cast (growth/128 as varchar(10))+ '' MB - ''
                                                                              when 1 then cast (growth as varchar(10)) + ''% - '' ELSE '''' END
                                                                              + CASE MAX_SIZE WHEN 0 THEN '' DISABLED '' 
                                                                                              WHEN -1 THEN '' UNRESTRICTED''
                                                                                              ELSE '' RESTRICTED TO '' + CAST(MAX_SIZE/(128*1024) AS VARCHAR(10)) + '' GB '' END
                                                                            + CASE IS_PERCENT_GROWTH WHEn 1 then '' [autogrowth by percent]'' else '''' end
                from sys.database_files A
                left join sys.filegroups fg on a.data_space_id = fg.data_space_id
                order by A.type desc,A.name
                ;
                '
            
                --print @sql
            
                EXEC sp_MSforeachdb @SQL
                go
            
                SELECT dbSize.*,fg.*,d.log_reuse_wait_desc,d.recovery_model_desc
                FROM #tempFileInformation fg
                LEFT JOIN sys.databases d on fg.DBNAME = d.name
                CROSS APPLY
                (
                    select dbname,
                            sum(FILESIZE_MB) as [totalDBSize_MB],
                            sum(FREESPACE_MB) as [DB_Free_Space_Size_MB],
                            sum(USEDSPACE_MB) as [DB_Used_Space_Size_MB]
                        from #tempFileInformation
                        where  dbname = fg.dbname
                        group by dbname
                )dbSize
            
            
            go
            DROP TABLE #tempFileInformation
            

            【讨论】:

              【解决方案9】:

              此脚本列出了您正在寻找的大部分内容,并有望根据您的需要进行修改。请注意,它在那里创建了一个永久表 - 您可能想要更改它。它是一个更大脚本的子集,它还总结了各种服务器上的备份和作业信息。

              IF OBJECT_ID('tempdb..#DriveInfo') IS NOT NULL
               DROP TABLE #DriveInfo
              CREATE TABLE #DriveInfo
               (
                  Drive CHAR(1)
                  ,MBFree INT
               ) 
              
              INSERT  INTO #DriveInfo
                    EXEC master..xp_fixeddrives
              
              
              IF OBJECT_ID('[dbo].[Tmp_tblDatabaseInfo]', 'U') IS NOT NULL 
                 DROP TABLE [dbo].[Tmp_tblDatabaseInfo]
              CREATE TABLE [dbo].[Tmp_tblDatabaseInfo](
                    [ServerName] [nvarchar](128) NULL
                    ,[DBName] [nvarchar](128)  NULL
                    ,[database_id] [int] NULL
                    ,[create_date] datetime NULL
                    ,[CompatibilityLevel] [int] NULL
                    ,[collation_name] [nvarchar](128) NULL
                    ,[state_desc] [nvarchar](60) NULL
                    ,[recovery_model_desc] [nvarchar](60) NULL
                    ,[DataFileLocations] [nvarchar](4000)
                    ,[DataFilesMB] money null
                    ,DataVolumeFreeSpaceMB INT NULL
                    ,[LogFileLocations] [nvarchar](4000)
                    ,[LogFilesMB] money null
                    ,LogVolumeFreeSpaceMB INT NULL
              
              ) ON [PRIMARY]
              
              INSERT INTO [dbo].[Tmp_tblDatabaseInfo] 
              SELECT 
                    @@SERVERNAME AS [ServerName] 
                    ,d.name AS DBName 
                    ,d.database_id
                    ,d.create_date
                    ,d.compatibility_level  
                    ,CAST(d.collation_name AS [nvarchar](128)) AS collation_name
                    ,d.[state_desc]
                    ,d.recovery_model_desc
                    ,(select physical_name + ' | ' AS [text()]
                       from sys.master_files m
                       WHERE m.type = 0 and m.database_id = d.database_id
                       ORDER BY file_id
                       FOR XML PATH ('')) AS DataFileLocations
                    ,(select sum(size) from sys.master_files m WHERE m.type = 0 and m.database_id = d.database_id)  AS DataFilesMB
                    ,NULL
                    ,(select physical_name + ' | ' AS [text()]
                       from sys.master_files m
                       WHERE m.type = 1 and m.database_id = d.database_id
                       ORDER BY file_id
                       FOR XML PATH ('')) AS LogFileLocations
                    ,(select sum(size) from sys.master_files m WHERE m.type = 1 and m.database_id = d.database_id)  AS LogFilesMB
                    ,NULL
              FROM  sys.databases d  
              
              WHERE d.database_id > 4 --Exclude basic system databases
              UPDATE [dbo].[Tmp_tblDatabaseInfo] 
                 SET DataFileLocations = 
                    CASE WHEN LEN(DataFileLocations) > 4 THEN  LEFT(DataFileLocations,LEN(DataFileLocations)-2) ELSE NULL END
                 ,LogFileLocations =
                    CASE WHEN LEN(LogFileLocations) > 4 THEN  LEFT(LogFileLocations,LEN(LogFileLocations)-2) ELSE NULL END
                 ,DataFilesMB = 
                    CASE WHEN DataFilesMB > 0 THEN  DataFilesMB * 8 / 1024.0   ELSE NULL END
                 ,LogFilesMB = 
                    CASE WHEN LogFilesMB > 0 THEN  LogFilesMB * 8 / 1024.0  ELSE NULL END
                 ,DataVolumeFreeSpaceMB = 
                    (SELECT MBFree FROM #DriveInfo WHERE Drive = LEFT( DataFileLocations,1))
                 ,LogVolumeFreeSpaceMB = 
                    (SELECT MBFree FROM #DriveInfo WHERE Drive = LEFT( LogFileLocations,1))
              
              select * from [dbo].[Tmp_tblDatabaseInfo] 
              

              【讨论】:

              • 一个优秀的脚本,可以复制/粘贴并按原样使用。不过有一个问题,我看到LogVolumeFreeSpaceMB 总是显示所有文件的相同数量,在我的情况下为 44756。是否可以获得实际的可用空间?或者是 LDF 所在驱动器上的最大可用空间数?
              • 嗨,Abel - 我已经有一段时间没有写信了,我不太确定你的问题。 XP_FIXEDDRIVES 有一个替代方法,称为 sys.dm_os_volume_stats,因此您可以尝试使用它。如果问题是数据库的文件大小没有随时间变化,那么这是正常的,因为 SQL Server 会分配一大块空磁盘空间供其使用,然后在文件被填满之前不会扩展该文件。它将在跳转中扩展文件,其数量由该特定数据库的文件设置确定
              【解决方案10】:

              如果重命名数据库,MS SQL Server 不会重命名基础文件。

              以下查询为您提供数据库的当前名称和逻辑文件名(可能是数据库创建时的原始名称)以及相应的物理文件名。

              注意:取消注释最后一行以仅查看实际数据文件

              select  db.database_id, 
                      db.name "Database Name", 
                      files.name "Logical File Name",
                      files.physical_name
              from    sys.master_files files 
                      join sys.databases db on db.database_id = files.database_id 
              --                           and files.type_desc = 'ROWS'
              

              参考:

              https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-master-files-transact-sql?view=sql-server-ver15

              https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-ver15

              【讨论】:

                【解决方案11】:

                要避免在多个数据文件(例如“.ndf”文件类型)存在时出现错误的查询,试试这个版本,它用连接替换子查询。

                这是使用联接而不是子查询的查询版本。

                干杯!

                SELECT
                    db.name AS DBName,
                    db.database_id,
                    mfr.physical_name AS DataFile,
                    mfl.physical_name AS LogFile
                FROM sys.databases db
                    JOIN sys.master_files mfr ON db.database_id=mfr.database_id AND mfr.type_desc='ROWS'
                    JOIN sys.master_files mfl ON db.database_id=mfl.database_id AND mfl.type_desc='LOG'
                ORDER BY db.database_id
                

                示例结果: (请注意,单个日志文件与单个数据库的每个 MDF 和 NDF 配对)

                【讨论】:

                  【解决方案12】:

                  只需加上我的 2 美分。

                  如果专门寻找仅在数据文件中或仅在所有数据库的日志文件中查找总可用空间,我们可以使用“data_space_id”列。 1 用于数据文件,0 用于日志文件。

                  代码:

                  Create Table ##temp
                  (
                      DatabaseName sysname,
                      Name sysname,
                      spacetype sysname,
                      physical_name nvarchar(500),
                      size decimal (18,2),
                      FreeSpace decimal (18,2)
                  )   
                  Exec sp_msforeachdb '
                  Use [?];
                  
                  Insert Into ##temp (DatabaseName, Name,spacetype, physical_name, Size, FreeSpace)
                      Select DB_NAME() AS [DatabaseName], Name,   ***data_space_id*** , physical_name,
                      Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2) as decimal(18,2))/1024 as nvarchar) SizeGB,
                      Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2)/1024 as decimal(18,2)) -
                          Cast(FILEPROPERTY(name, ''SpaceUsed'') * 8.0/1024.0 as decimal(18,2))/1024 as nvarchar) As FreeSpaceGB
                      From sys.database_files'
                  
                  
                  select  
                      databasename
                      , sum(##temp.FreeSpace) 
                  from 
                      ##temp 
                  where 
                      ##temp.spacetype = 1  
                  group by 
                      DatabaseName
                  
                  drop table ##temp 
                  
                  

                  【讨论】:

                    【解决方案13】:

                    使用 sp_MSForEachDB 存储过程是一种选择

                    EXEC sp_MSForEachDB 'use ? select * from sys.database_files'
                    

                    另外仅查看完整路径名称和大小信息

                    EXEC sp_MSForEachDB '
                    USE [?];
                    SELECT DB_NAME() AS DbName, 
                        physical_name AS FullPath,
                        name AS FileName, 
                        type_desc,
                        size/128.0 AS CurrentSizeMB,  
                        size/128.0 - CAST(FILEPROPERTY(name, ''SpaceUsed'') AS INT)/128.0 AS FreeSpaceMB
                    FROM sys.database_files
                    WHERE type IN (0,1);
                    '
                    

                    【讨论】:

                      【解决方案14】:

                      您可以使用以下内容:

                      SP_HELPDB [Master]
                      GO
                      

                      【讨论】:

                      • 这仅提供单个指定数据库的信息。问题适用于所有数据库。
                      猜你喜欢
                      • 2018-02-07
                      • 1970-01-01
                      • 2011-02-23
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-02-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-09-29
                      相关资源
                      最近更新 更多