1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > SQL Server系统视图sys.master_files不能正确显示数据库脱机状态

SQL Server系统视图sys.master_files不能正确显示数据库脱机状态

时间:2018-06-16 18:13:18

相关推荐

SQL Server系统视图sys.master_files不能正确显示数据库脱机状态

SQL Server系统视图sys.master_files不能正确显示数据库脱机状态 原文: SQL Server系统视图sys.master_files不能正确显示数据库脱机状态

最近发现在SQL Server数据库(目前测试过SQL Server , ,,各个版本)中,即使数据库处于脱机(OFFLINE)状态,但是sys.master_files中依然显示是联机状态。本文测试环境为Microsoft SQL Server (SP2) (KB3171021) - 12.0.5000.0 (X64) 。具体测试过程如下所示:

USE master;

GO

ALTERDATABASE TEST SET OFFLINE WITHROLLBACKIMMEDIATE;

GO

SELECT name ,

physical_name ,

state ,

state_desc

FROM sys.master_files

WHERE database_id = DB_ID('test');

SELECT name ,

state ,

state_desc

FROM sys.databases

WHERE name = 'test';

如上所示,sys.databases系统视图正确的显示数据库处于脱机状态(OFFLINE),但是系统视图sys.master_files显示的依然是联机(ONLINE),我们可以获取系统视图sys.master_files的定义,如下所示(至于如何获取视图定义,如果你不清楚,可以参考我的博客SQL Server查看视图定义总结),

SET QUOTED_IDENTIFIER ON

SET ANSI_NULLS ON

GO

CREATEVIEW 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),

credential_id = cr.credential_id

FROM sys.sysbrickfiles f

LEFTJOIN sys.syspalvalues st ON st.class = 'DBFS'AND st.value = f.filestate

LEFTJOIN sys.syspalvalues ft ON ft.class = 'DBFT'AND ft.value = f.filetype

LEFTJOIN sys.credentials cr ON f.pname LIKE cr.name + N'%'COLLATE database_default

WHERE f.dbid < 0x7fff -- consistent with sys.databases

AND f.pruid = 0

AND f.filestate NOTIN (1, 2) -- x_efs_Dummy, x_efs_Dropped

AND has_access('MF', 1) = 1

GO

可以看出sys.master_files的state值来自于系统基表sys.sysbrickfiles的filestate字段,我们从DAC模式去查看,发现TEST数据库(dbid=21)的filestat为0,这个值应该为6才对,另外,还有一个让人意外的是,这个系统表里面关于TEST数据库有两个事务日志文件记录,实际上只有一个(其实这个是前阵子写这篇博客“MS SQL 事务日志管理小结”时,测试添加、删除数据事务日志文件遗留下来的记录,不清楚是Bug还是什么问题导致在系统基表还存在这样的一条记录)

那么我们接下来看看sys.sysbrickfiles的具体定义,如下所示:

SET QUOTED_IDENTIFIER ON

SET ANSI_NULLS ON

GO

CREATEVIEW sys.databases AS

SELECT d.name, d.id AS database_id,

r.indepid AS source_database_id,

d.sid AS owner_sid,

d.crdate AS create_date,

d.cmptlevel AS compatibility_level,

-- coll.value = null means that a collation wasn't specified for the DB and the server default is used instead

convert(sysname, case when serverproperty('EngineEdition') = 5 AND d.id = 1 then serverproperty('collation')

else CollationPropertyFromID(convert(int, isnull(coll.value, p.cid)), 'name') end) AS collation_name,

p.user_access, ua.name AS user_access_desc,

sysconv(bit, d.status & 0x400) AS is_read_only, -- DBR_RDONLY

sysconv(bit, d.status & 1) AS is_auto_close_on, -- DBR_CLOSE_ON_EXIT

sysconv(bit, d.status & 0x400000) AS is_auto_shrink_on, -- DBR_AUTOSHRINK

case when (serverproperty('EngineEdition') = 5) AND (sysconv(bit, d.status & 0x00000020) = 1) then cast (1 as tinyint) -- RESTORING

when (serverproperty('EngineEdition') = 5) AND (sysconv(bit, d.status & 0x00000080) = 1) then cast (7 as tinyint) -- COPYING

when (serverproperty('EngineEdition') = 5) AND (sysconv(bit, d.status & 0x00000100) = 1) then cast (4 as tinyint) -- SUSPECT

else p.state

end AS state, -- 7 is COPYING and 4 is SUSPECT state for database copy (UNDO: Need to have a clean way to set states in dbtable for a user db)

case when (serverproperty('EngineEdition') = 5) AND (sysconv(bit, d.status & 0x00000020) = 1) then 'RESTORING'

when (serverproperty('EngineEdition') = 5) AND (sysconv(bit, d.status & 0x00000080) = 1) then 'COPYING'

when (serverproperty('EngineEdition') = 5) AND (sysconv(bit, d.status & 0x00000100) = 1) then 'SUSPECT'

else st.name

end AS state_desc,

sysconv(bit, d.status & 0x200000) AS is_in_standby, -- DBR_STANDBY

case when serverproperty('EngineEdition') = 5 then convert(bit, 0) else p.is_cleanly_shutdown end AS is_cleanly_shutdown,

sysconv(bit, d.status & 0x80000000) AS is_supplemental_logging_enabled, -- DBR_SUPPLEMENT_LOG

p.snapshot_isolation_state, si.name AS snapshot_isolation_state_desc,

sysconv(bit, d.status & 0x800000) AS is_read_committed_snapshot_on, -- DBR_READCOMMITTED_SNAPSHOT

p.recovery_model, ro.name AS recovery_model_desc,

p.page_verify_option, pv.name AS page_verify_option_desc,

sysconv(bit, d.status2 & 0x1000000) AS is_auto_create_stats_on, -- DBR_AUTOCRTSTATS

sysconv(bit, d.status2 & 0x00400000) AS is_auto_create_stats_incremental_on, -- DBR_AUTOCRTSTATSINC

sysconv(bit, d.status2 & 0x40000000) AS is_auto_update_stats_on, -- DBR_AUTOUPDSTATS

sysconv(bit, d.status2 & 0x80000000) AS is_auto_update_stats_async_on, -- DBR_AUTOUPDSTATSASYNC

sysconv(bit, d.status2 & 0x4000) AS is_ansi_null_default_on, -- DBR_ANSINULLDFLT

sysconv(bit, d.status2 & 0x4000000) AS is_ansi_nulls_on, -- DBR_ANSINULLS

sysconv(bit, d.status2 & 0x2000) AS is_ansi_padding_on, -- DBR_ANSIPADDING

sysconv(bit, d.status2 & 0x10000000) AS is_ansi_warnings_on, -- DBR_ANSIWARNINGS

sysconv(bit, d.status2 & 0x1000) AS is_arithabort_on, -- DBR_ARITHABORT

sysconv(bit, d.status2 & 0x10000) AS is_concat_null_yields_null_on, -- DBR_CATNULL

sysconv(bit, d.status2 & 0x800) AS is_numeric_roundabort_on, -- DBR_NUMEABORT

sysconv(bit, d.status2 & 0x800000) AS is_quoted_identifier_on, -- DBR_QUOTEDIDENT

sysconv(bit, d.status2 & 0x20000) AS is_recursive_triggers_on, -- DBR_RECURTRIG

sysconv(bit, d.status2 & 0x2000000) AS is_cursor_close_on_commit_on, -- DBR_CURSCLOSEONCOM

sysconv(bit, d.status2 & 0x100000) AS is_local_cursor_default, -- DBR_DEFLOCALCURS

sysconv(bit, d.status2 & 0x20000000) AS is_fulltext_enabled, -- DBR_FTENABLED

sysconv(bit, d.status2 & 0x200) AS is_trustworthy_on, -- DBR_TRUSTWORTHY

sysconv(bit, d.status2 & 0x400) AS is_db_chaining_on, -- DBR_DBCHAINING

sysconv(bit, d.status2 & 0x08000000) AS is_parameterization_forced, -- DBR_UNIVERSALAUTOPARAM

sysconv(bit, d.status2 & 64) AS is_master_key_encrypted_by_server, -- DBR_MASTKEY

sysconv(bit, d.status2 & 0x00000010) AS is_query_store_on, -- DBR_QDSENABLED

sysconv(bit, d.category & 1) AS is_published,

sysconv(bit, d.category & 2) AS is_subscribed,

sysconv(bit, d.category & 4) AS is_merge_published,

sysconv(bit, d.category & 16) AS is_distributor,

sysconv(bit, d.category & 32) AS is_sync_with_backup,

d.svcbrkrguid AS service_broker_guid,

sysconv(bit, case when d.scope = 0 then 1 else 0 end) AS is_broker_enabled,

p.log_reuse_wait, lr.name AS log_reuse_wait_desc,

sysconv(bit, d.status2 & 4) AS is_date_correlation_on, -- DBR_DATECORRELATIONOPT

sysconv(bit, d.category & 64) AS is_cdc_enabled,

sysconv(bit, d.status2 & 0x100) AS is_encrypted, -- DBR_ENCRYPTION

convert(bit, d.status2 & 0x8) AS is_honor_broker_priority_on, -- DBR_HONORBRKPRI

sgr.guid AS replica_id,

sgr2.guid AS group_database_id,

ssr.indepid AS resource_pool_id,

default_language_lcid = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(smallint, p.default_language) else null end,

default_language_name = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(sysname, sld.name) else null end,

default_fulltext_language_lcid = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(int, p.default_fulltext_language) else null end,

default_fulltext_language_name = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(sysname, slft.name) else null end,

is_nested_triggers_on = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(bit, p.allow_nested_triggers) else null end,

is_transform_noise_words_on = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(bit, p.transform_noise_words) else null end,

two_digit_year_cutoff = case when ((d.status2 & 0x80000)=0x80000 AND p.containment = 1) then convert(smallint, p.two_digit_year_cutoff) else null end,

containment = sysconv(tinyint, (d.status2 & 0x80000)/0x80000), -- DBR_IS_CDB

containment_desc = convert(nvarchar(60), cdb.name),

p.recovery_seconds AS target_recovery_time_in_seconds,

p.delayed_durability,

case when (p.delayed_durability = 0) then CAST('DISABLED' AS nvarchar(60)) -- LCOPT_DISABLED

when (p.delayed_durability = 1) then CAST('ALLOWED' AS nvarchar(60)) -- LCOPT_ALLOWED

when (p.delayed_durability = 2) then CAST('FORCED' AS nvarchar(60)) -- LCOPT_FORCED

else NULL

end AS delayed_durability_desc,

convert(bit, d.status2 & 0x80) AS is_memory_optimized_elevate_to_snapshot_on -- DBR_HKELEVATETOSNAPSHOT

FROM sys.sysdbreg d OUTER APPLY OpenRowset(TABLE DBPROP, (case when serverproperty('EngineEdition') = 5 then DB_ID() else d.id end)) p

LEFT JOIN sys.syssingleobjrefs r ON r.depid = d.id AND r.class = 96 AND r.depsubid = 0 -- SRC_VIEWPOINTDB

LEFT JOIN sys.syspalvalues st ON st.class = 'DBST' AND st.value = p.state

LEFT JOIN sys.syspalvalues ua ON ua.class = 'DBUA' AND ua.value = p.user_access

LEFT JOIN sys.syspalvalues si ON si.class = 'DBSI' AND si.value = p.snapshot_isolation_state

LEFT JOIN sys.syspalvalues ro ON ro.class = 'DBRO' AND ro.value = p.recovery_model

LEFT JOIN sys.syspalvalues pv ON pv.class = 'DBPV' AND pv.value = p.page_verify_option

LEFT JOIN sys.syspalvalues lr ON lr.class = 'LRWT' AND lr.value = p.log_reuse_wait

LEFT JOIN sys.syssingleobjrefs agdb ON agdb.depid = d.id AND agdb.class = 104 AND agdb.depsubid = 0 -- SRC_AVAILABILITYGROUP

LEFT JOIN master.sys.syssingleobjrefs ssr ON ssr.class = 108 AND ssr.depid = d.id -- SRC_RG_DB_TO_POOL

LEFT JOIN master.sys.sysclsobjs ag ON ag.id = agdb.indepid AND ag.class = 67 -- SOC_AVAILABILITY_GROUP

LEFT JOIN master.sys.sysguidrefs sgr ON sgr.class = 8 AND sgr.id = ag.id AND sgr.subid = 1 -- GRC_AGGUID / AGGUID_REPLICA_ID

LEFT JOIN master.sys.sysguidrefs sgr2 ON sgr2.class = 9 AND sgr2.id = ag.id AND sgr2.subid = d.id -- GRC_AGDBGUID

LEFT JOIN sys.syspalvalues cdb ON cdb.class = 'DCDB' AND cdb.value = CASE WHEN (d.status2 & 0x80000)=0x80000 THEN 1 ELSE 0 END

LEFT JOIN sys.syslanguages sld ON sld.lcid = p.default_language

LEFT JOIN sys.fulltext_languages slft ON slft.lcid = p.default_fulltext_language

LEFT JOIN sys.sysobjvalues coll ON coll.valclass = 102 AND coll.subobjid = 0 AND coll.objid = d.id -- SVC_DATACOLLATION

WHERE d.id < 0x7fff

AND has_access('DB', (case when serverproperty('EngineEdition') = 5 then DB_ID() else d.id end)) = 1

GO

因为当前数据库版本为标准版,所以stated的值来自OpenRowset(TABLE DBPROP, (case when serverproperty('EngineEdition') = 5 then DB_ID() else d.id end)) p

我们可以在单用户专用连接服务器模式下查看相关记录的值。如下截图所示:

其实发现这个问题(其实我更愿意称其为一个bug)是一次查询时的意外发现。实验测试让我有点吃惊。居然这么多版本都是这种情况! 这到底是一个“bug”还是数据库什么内部机制呢?

posted on -08-03 08:35 NET未来之路 阅读( ...) 评论( ...) 编辑 收藏

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。