SQL Server使用sys.master_files计算tempdb大小不正确

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 一直习惯使用sys.master_files来统计数据库的大小以及使用情况,但是发现sys.master_files不能准确统计tempdb的数据库大小信息。如下所示:     SELECT       database_id                                AS ...

一直习惯使用sys.master_files来统计数据库的大小以及使用情况,但是发现sys.master_files不能准确统计tempdb的数据库大小信息。如下所示:

 

 

SELECT       database_id                                AS DataBaseId 
            ,DB_NAME(database_id)                       AS DataBaseName 
            ,Name                                       AS LogicalName 
            ,type_desc                                  AS FileTypeDesc 
            ,Physical_Name                              AS PhysicalName 
            ,State_Desc                                 AS StateDesc 
            ,CASE WHEN max_size = 0  THEN N'不允许增长'
                  WHEN max_size = -1 THEN N'自动增长'
             ELSE LTRIM(STR(max_size * 8.0 / 1024 / 1024, 14, 2))
                      + 'G'
             END                                    AS MaxSize 
            ,CASE WHEN is_percent_growth = 1
                 THEN RTRIM(CAST(Growth AS CHAR(10))) + '%'
                 ELSE RTRIM(CAST(Growth*8.0/1024 AS CHAR(10))) + 'M'
            END                                          AS Growth 
            ,Is_Read_Only                                AS IsReadOnly 
            ,Is_Percent_Growth                           AS IsPercentGrowth 
            ,CAST(size * 8.0 / 1024 / 1024 AS DECIMAL(8, 4)) AS [Size(GB)]
FROM     sys.master_files
WHERE database_id =2
ORDER BY 1

 

 

clip_image001

 

 

Windows窗口里,你会看到这些文件实际大小为18G多,而不是1G大小,而使用sys.master_files统计的SizeGB)仅仅是tempdb文件的初始化大小,当然,你在SSMS里面使用UI去查看tempdb的属性发现其大小值又是正确的,

 

 

 

clip_image002

 

 

clip_image003

 

 

如果你用Profile跟踪看看具体SQL如下,你会发现,它统计的数据来源于视图sys.database_files

 

 

USE tempdb;
GO
SELECT  s.name AS [Name] ,
        CAST(FILEPROPERTY(s.name, 'SpaceUsed') AS FLOAT) * CONVERT(FLOAT, 8) AS [UsedSpace] ,
        CAST(CASE WHEN s.growth = 0 THEN ( CASE WHEN s.type = 2 THEN 0
                                                ELSE 99
                                           END )
                  ELSE s.is_percent_growth
             END AS INT) AS [GrowthType] ,
        s.physical_name AS [FileName] ,
        s.size * CONVERT(FLOAT, 8) AS [Size] ,
        CASE WHEN s.max_size = -1 THEN -1
             ELSE s.max_size * CONVERT(FLOAT, 8)
        END AS [MaxSize] ,
        s.file_id AS [ID] ,
        'Server[@Name='
        + QUOTENAME(CAST(SERVERPROPERTY(N'Servername') AS sysname), '''')
        + ']' + '/Database[@Name=' + QUOTENAME(DB_NAME(), '''') + ']'
        + '/LogFile[@Name=' + QUOTENAME(s.name, '''') + ']' AS [Urn] ,
        CAST(CASE s.is_percent_growth
               WHEN 1 THEN s.growth
               ELSE s.growth * 8
             END AS FLOAT) AS [Growth] ,
        s.is_media_read_only AS [IsReadOnlyMedia] ,
        s.is_read_only AS [IsReadOnly] ,
        CAST(CASE s.state
               WHEN 6 THEN 1
               ELSE 0
             END AS BIT) AS [IsOffline] ,
        s.is_sparse AS [IsSparse]
FROM    sys.database_files AS s
WHERE   ( s.type = 1 )
ORDER BY [Name] ASC;

 

 

 

sys.database_files的具体定义如下

 

 

SET quoted_identifier ON 
SET ansi_nulls ON 
 
go 
 
CREATE VIEW sys.database_files 
AS 
  SELECT file_id = f.fileid, 
         file_guid = f.fileguid, 
         type = f.filetype, 
         type_desc = ft.NAME, 
         data_space_id = f.grpid, 
         NAME = f.lname, 
         physical_name = f.pname, 
         state = CONVERT(TINYINT, CASE f.filestate 
                                    -- Map enum EMDFileState to AvailablityStates 
                                    WHEN 0 THEN 0 
                                    WHEN 10 THEN 0 -- ONLINE 
                                    WHEN 4 THEN 7 -- DEFUNCT 
                                    WHEN 5 THEN 3 
                                    WHEN 9 THEN 3 -- RECOVERY_PENDING 
                                    WHEN 7 THEN 1 
                                    WHEN 8 THEN 1 
                                    WHEN 11 THEN 1 -- RESTORING 
                                    WHEN 12 THEN 4 -- SUSPECT 
                                    ELSE 6 
                                  END),-- OFFLINE 
         state_desc = st.NAME, 
         size = Isnull(Filepropertybyid(f.fileid, 'size'), size), 
         max_size = f.maxsize, 
         f.growth, 
         is_media_read_only = Sysconv(bit, f.status & 8),-- FIL_READONLY_MEDIA 
         is_read_only = Sysconv(bit, f.status & 16),-- FIL_READONLY 
         is_sparse = Sysconv(bit, f.status & 256),-- FIL_SPARSE_FILE 
         is_percent_growth = Sysconv(bit, f.status & 32),-- FIL_PERCENT_GROWTH 
         is_name_reserved = Sysconv(bit, CASE f.filestate 
                                           WHEN 3 THEN 1 
                                           ELSE 0 
                                         END),-- x_efs_DroppedReusePending 
         create_lsn = Getnumericlsn(f.createlsn), 
         drop_lsn = Getnumericlsn(f.droplsn), 
         read_only_lsn = Getnumericlsn(f.readonlylsn), 
         read_write_lsn = Getnumericlsn(f.readwritelsn), 
         differential_base_lsn = Getnumericlsn(f.diffbaselsn), 
         differential_base_guid = f.diffbaseguid, 
         differential_base_time = NULLIF(f.diffbasetime, 0), 
         redo_start_lsn = Getnumericlsn(f.redostartlsn), 
         redo_start_fork_guid = f.redostartforkguid, 
         redo_target_lsn = Getnumericlsn(f.redotargetlsn), 
         redo_target_fork_guid = f.forkguid, 
         backup_lsn = Getnumericlsn(f.backuplsn) 
  FROM   sys.sysprufiles f 
         LEFT JOIN sys.syspalvalues st 
                ON st.class = 'DBFS' 
                   AND st.value = f.filestate 
         LEFT JOIN sys.syspalvalues ft 
                ON ft.class = 'DBFT' 
                   AND ft.value = f.filetype 
  WHERE  filestate NOT IN ( 1, 2 ) -- x_efs_Dummy, x_efs_Dropped 
go 

 

sys.master_files的具体定义如下:

 

 

SET quoted_identifier ON 
SET ansi_nulls ON 
 
go 
 
CREATE VIEW sys.master_files 
AS 
  SELECT database_id = f.dbid, 
         file_id = f.fileid, 
         file_guid = f.fileguid, 
         type = f.filetype, 
         type_desc = ft.NAME, 
         data_space_id = f.grpid, 
         NAME = f.lname, 
         physical_name = f.pname, 
         state = CONVERT(TINYINT, CASE f.filestate 
                                    -- Map enum EMDFileState to AvailablityStates 
                                    WHEN 0 THEN 0 
                                    WHEN 10 THEN 0 -- ONLINE 
                                    WHEN 4 THEN 7 -- DEFUNCT 
                                    WHEN 5 THEN 3 
                                    WHEN 9 THEN 3 -- RECOVERY_PENDING 
                                    WHEN 7 THEN 1 
                                    WHEN 8 THEN 1 
                                    WHEN 11 THEN 1 -- RESTORING 
                                    WHEN 12 THEN 4 -- SUSPECT 
                                    ELSE 6 
                                  END),-- OFFLINE 
         state_desc = st.NAME, 
         f.size, 
         max_size = f.maxsize, 
         f.growth, 
         is_media_read_only = Sysconv(bit, f.status & 8),-- FIL_READONLY_MEDIA 
         is_read_only = Sysconv(bit, f.status & 16),-- FIL_READONLY 
         is_sparse = Sysconv(bit, f.status & 256),-- FIL_SPARSE_FILE 
         is_percent_growth = Sysconv(bit, f.status & 32),-- FIL_PERCENT_GROWTH 
         is_name_reserved = Sysconv(bit, CASE f.filestate 
                                           WHEN 3 THEN 1 
                                           ELSE 0 
                                         END),-- x_efs_DroppedReusePending 
         create_lsn = Getnumericlsn(f.createlsn), 
         drop_lsn = Getnumericlsn(f.droplsn), 
         read_only_lsn = Getnumericlsn(f.readonlylsn), 
         read_write_lsn = Getnumericlsn(f.readwritelsn), 
         differential_base_lsn = Getnumericlsn(f.diffbaselsn), 
         differential_base_guid = f.diffbaseguid, 
         differential_base_time = NULLIF(f.diffbasetime, 0), 
         redo_start_lsn = Getnumericlsn(f.redostartlsn), 
         redo_start_fork_guid = f.redostartforkguid, 
         redo_target_lsn = Getnumericlsn(f.redotargetlsn), 
         redo_target_fork_guid = f.forkguid, 
         backup_lsn = Getnumericlsn(f.backuplsn) 
  FROM   master.sys.sysbrickfiles f 
         LEFT JOIN sys.syspalvalues st 
                ON st.class = 'DBFS' 
                   AND st.value = f.filestate 
         LEFT JOIN sys.syspalvalues ft 
                ON ft.class = 'DBFT' 
                   AND ft.value = f.filetype 
  WHERE  f.dbid < 0x7fff -- consistent with sys.databases 
         AND f.pruid = 0 
         AND f.filestate NOT IN ( 1, 2 ) -- x_efs_Dummy, x_efs_Dropped 
         AND Has_access('MF', 1) = 1 
 
go 

 

从上面SQL脚本可以看到,统计数据库的大小分别来自于sys.sysprufiles master.sys.sysbrickfiles这两个表,然后我们就很难再深入了解具体的原因了。在https://connect.microsoft.com/SQLServer/feedback/details/377223/sys-master-files-does-not-show-accurate-size-information 这个链接里面,对tempdb相关的问题有一些描述:

 

 

1. The view sys.master_files is something new and is updated asynchronously. It doesn't updates immediately.

2. When you re-start your SQL Server, SQL Server will re-create tempdb based on sys.master_files.

3. The sys.master_files tell you about any tempdb data file which was there on your system (the number of tempdb files) with which your server have started.

4. While sys.database_files shows currently used tempdb files. Its quite possible that not all tempdb data files came online.

5. You can read the errorlog look for any error meesage did any of the files did not come online.

6. After you started sql server somebody might have executed SQL commands to remove or add tempdb files.

 

 

 

大体意思,sys.master_files中的数据是异步更新的,而不是同步更新的。它不会立即更新。当你重启你的SQL Server时,SQL Server启动时候都会根据sys.master_files中值重新创建、初始化tempdb文件大小。而sys.database_files显示当前使用的tempdb文件。 很可能并非所有的tempdb数据文件都在线。 所以,如果要查询tempdb的准确大小,就要使用sys.database_files来查询!

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
相关文章
|
2月前
|
SQL 存储 缓存
SQL计算班级语文平均分:详细步骤与技巧
在数据库管理和分析中,经常需要计算某个班级在特定科目上的平均分
|
3月前
|
SQL 存储 并行计算
Lindorm Ganos 一条 SQL 计算轨迹
Lindorm Ganos 针对轨迹距离计算场景提供了内置函数 ST_Length_Rows,结合原生时空二级索引和时空聚合计算下推技术,能够高效过滤数据并并行执行运算任务。该方案通过主键索引和时空索引快速过滤数据,并利用多Region并行计算轨迹点距离,适用于车联网等场景。具体步骤包括根据车辆识别代码和时间戳过滤数据、范围过滤轨迹点以及并行计算距离。使用限制包括只支持点类型列聚合运算及表中轨迹点需按顺序排列等。测试结果显示,Lindorm Ganos 在不同数据量下均能实现秒级响应。
32 3
|
3月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
5月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
129 13
|
5月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
5月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
69 6
|
4月前
|
SQL 数据挖掘 数据库
SQL计算班级语文平均分:详细步骤与技巧
在数据库管理中,经常需要统计和查询各种汇总信息,如班级某科目的平均分
|
4月前
|
SQL 安全 Java
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
528 0
|
5月前
|
SQL 监控 数据库
SQL Server 查询超时问题排查
【7月更文挑战第8天】排查 SQL Server 查询超时涉及五个主要方面:检查复杂查询、评估服务器性能、审视配置参数、更新统计信息和分析执行计划。关注点包括查询的结构(如连接、子查询和索引),服务器资源(CPU、内存、网络延迟),连接和内存设置,以及统计信息的时效性。通过这些步骤可定位并解决性能瓶颈。
134 0
|
3月前
|
SQL 数据库
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
SQL Server附加数据库出现错误823,附加数据库失败。数据库没有备份,无法通过备份恢复数据库。 SQL Server数据库出现823错误的可能原因有:数据库物理页面损坏、数据库物理页面校验值损坏导致无法识别该页面、断电或者文件系统问题导致页面丢失。
105 12
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例