zoukankan      html  css  js  c++  java
  • SQL Server系统视图sys.master_files不能正确显示数据库脱机状态

     

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

     

     

     
    USE master;
    GO
    ALTER DATABASE TEST SET OFFLINE WITH ROLLBACK IMMEDIATE;
    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';

     

     

    clip_image001

     

     

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

     

     

     

    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),
            credential_id             = cr.credential_id
        FROM 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
        LEFT JOIN 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 NOT IN (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还是什么问题导致在系统基表还存在这样的一条记录

     

     

     

    clip_image002

     

     

     

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

     

    SET QUOTED_IDENTIFIER ON
    SET ANSI_NULLS ON
    GO
    CREATE VIEW 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

     

     

     

     

     

     

    EngineEdition

    服务器上安装的 数据库引擎 实例的 SQL Server版本。

    1 = Personal 或 Desktop Engine(不适用于 SQL Server 2005?和更高版本。)

    2 = Standard(对 Standard、Web 和 Business Intelligence 返回该值。)

    3 = Enterprise(对 Enterprise、Developer 以及两个 Enterprise 版本返回该值。)

    4 = Express(对 Express、Express with Tools 和 Express with Advanced Services 返回该值)

    5 = SQL Database

    6 = SQL 数据仓库

    8 = 托管实例

    基本数据类型:int

     

     

     

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

     

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

     

     

    clip_image003

     

     

    clip_image004

     

     

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

  • 相关阅读:
    Codechef EDGEST 树套树 树状数组 线段树 LCA 卡常
    BZOJ4319 cerc2008 Suffix reconstruction 字符串 SA
    Codechef STMINCUT S-T Mincut (CodeChef May Challenge 2018) kruskal
    Codeforces 316G3 Good Substrings 字符串 SAM
    Codechef CHSIGN Change the Signs(May Challenge 2018) 动态规划
    BZOJ1396 识别子串 字符串 SAM 线段树
    CodeForces 516C Drazil and Park 线段树
    CodeForces 516B Drazil and Tiles 其他
    CodeForces 516A Drazil and Factorial 动态规划
    SPOJ LCS2
  • 原文地址:https://www.cnblogs.com/kerrycode/p/8894851.html
Copyright © 2011-2022 走看看