DBCC在sqlserver 2000后的含义为Database Console Commands,即数据库控制台命令。其中最常用的命令有以下几个:
DBCC HELP:得到DBCC命令帮助信息
DBCC EXTENTINFO:查看指定对象分配到的区信息(非公开命令)
DBCC IND:查看指定对象分配到的数据页信息(非公开命令)
DBCC PAGE:以不同格式导出指定数据页中的数据(非公开命令)
DBCC FILEHEADER:查看数据文件文件头数据
DBCC DBINFO:查看数据库启动页中信息
- DBCC HELP
提供两个功能:
- 使用?作参数
返回所有dbcc命令列表,若开启2588跟踪标记,则还包括非公开命令
dbcc help('?')
以下包含非公开命令
- 使用dbcc命令名称作参数
返回该命令语法信息,若开启2588跟踪标记,则还包括非公开命令(否则会报错)
查询公开命令
dbcc help('checkdb')
查询非公开命令
DBCC TRACEON(2588)
dbcc help('page')
- DBCC EXTENTINFO
查看指定对象分配到的区信息(非公开命令)
dbcc extentinfo [({'dbname'| dbid | 0} [, {'tablename' | tableid} [, {'indexname' | indexid | -1} [, partition_number]]])]
第一个参数:数据库名或ID。
第二个参数:表名或ID。
第三个参数:索引名或ID,如果指定为-1或省略,则显示表与其所有索引分配到的区信息
第四个参数:该参数是为兼容sql server 2000,是可选的;用于指定一个分区号。如果不给定值或者给定0, 则显示全部分区数据。
例子:查询hammerdb数据库中customer表与其所有索引分配到的区信息
dbcc extentinfo('hammerdb','customer')
字段含义
字段名称 | 说 明 |
file_id | 数据文件编号 |
page_id | 在某个分区中的第一个页面的页面号 |
pg_alloc | 该分区为数据库分配的页面数量m(1≤m≤8) |
ext_size | 分区的大小,以页面为单位 |
object_id | 数据库对象ID |
index_id | 表示数据对象的类型 |
partition_number | 分区号 |
rows | 大约的数据行数 |
hobt_id | 存储数据的堆或B树的存储单元ID |
- DBCC IND
DBCC IND 命令用于查看指定对象分配到的数据页信息,即对象的内部存储结构信息,可以通过对象名/id查到对应pageid,fileid等再通过DBCC PAGE查看对应页和文件具体信息
该命令有4个参数, 前3个参数必须指定。语法如下:
DBCC IND ( { 'dbname' | dbid }, { 'objname' | objid },{ nonclustered indid | 1 | 0 | -1 | -2 } [, partition_number] )
第一个参数:数据库名或ID。
第二个参数:数据库中的对象名或ID。
第三个参数:Nonclustered index ID或者1, 0, -1,-2。值的含义:
- Nonclustered index ID:显示索引的全部 IAM页, data页和索引页,包含LOB和 row-overflow数据页
- 0:只显示对象本身分配到的数据页和IAM 页信息。
- 1:显示对象的所有页信息:包含IAM页、数据页、LOB页和row-overflow 页。如果对象含有聚集索引,则也包括索引页。
- -1:显示对象及其上所有索引的所有页信息:包含IAM页、数据页、其上所有索引的索引页、LOB页和row-overflow 页
- -2:显示对象所有的IAM页。
第四个参数:该参数是为兼容sql server 2000,是可选的;用于指定一个分区号,如果不给定值或者给定0, 则显示全部分区数据。
和DBCC PAGE不同的是, SQL Server运行DBCC IND不需要开启3604跟踪标志.
我们来执行下列的命令:
DBCC IND('InternalStorageFormat','Customers',-1)
SQL Server会给我们如下的输出结果:
可以看到有2条记录,一条记录为页面类型(PageType)为10的页(IAM页)和一条记录为页面类型为1的页(数据页),它的页ID是79.
DBCC IND输出字段描述
Column(列) | Meaning(含义) |
PageFID | 页所在文件ID |
PagePID | 页ID |
IAMFID | 页对应的IAM页文件ID,IAM 页的IAMFID=NULL |
IAMPID | 页对应的IAM页ID,IAM 页的IAMPID=NULL |
ObjectID | 对象ID |
IndexID | 索引类型ID,0表示堆,1表示聚集索引,2-250表示非聚集索引。可以在sys.indexs上查找 |
PartitionNumber | 页所属分区号 |
PartitionID | 页所属分区内部编号 |
iam_chain_type | 页所属IAM链类型,为in-row data或row-overflow data或 LOB data三者之一 |
PageType | Page type: 1 = data page, 2 = index page, 3 = LOB_MIXED_PAGE, 4 = LOB_TREE_PAGE, 10 = IAM page |
IndexLevel | 索引级别,0表示叶子节点,根节点的级别最高 |
NextPageFID | 同一等级里后一个页所在文件的ID |
NextPagePID | 同一等级里后一个页的页ID |
PrevPageFID | 同一等级里前一个页所在文件的ID |
PrevPagePID | 同一等级里前一个页的页ID |
- DBCC PAGE
我们得到了数据页的页号为79,现在我们来看看79号数据页里存放的数据,这个就要用到DBCC PAGE,DBCC PAGE以不同格式导出指定数据页中的数据。语法如下:
DBCC Page ({dbid|dbname},filenum,pagenum[,printopt])
第一个参数:数据库名或ID。
第二个参数:文件号
第三个参数:页号
第四个参数:printopt指定输出格式:
- 0:默认值,输出缓冲区的标题和可读形式的页头数据
- 1:输出缓冲区的标题、可读形式的页头数据、每行记录的16进制数据及可读形式的偏移量表
- 2:输出缓冲区的标题、可读形式的页头数据、整个数据页的16进制数据及可读形式的偏移量表
- 3:输出缓冲区的标题、可读形式的页头数据、每行记录的16进制数据(每行后跟分别列出的它的列值)
设置DBCC TRACEON(3604)显示输出(否则输出会记入错误日志中)
DBCC TRACEON(3604)
DBCC PAGE(InternalStorageFormat,1,79,3)
GO
SQL Server会给我们包含4个部分的输出。
第1部分是BUFFER,里面是一些内存分配信息,对此我们没多少兴趣。
第2部分是固定96 bytes大小的页头(page header),页头会类似如下显示:
页头相关字段的含义:
- Page @0x08F84000 同BUFFER中的bpage地址
- m_pageId = (1:79) 文件号:页号
- m_headerVersion = 1 头文件版本号,一直为1
- m_type = 1 页面类型,1为数据页
- m_typeFlagBits = 0x4 数据页和索引页为4,其他页为0
- m_level = 0 该页在索引页中的级数,0为叶节点
- m_flagBits = 0x8000 数据页采用的IO错误保护类型(0x8200表示采用校验和保护方式,0x8100表示采用残缺页检测方式,0x8000为未开启)
- m_objId (AllocUnitId.idObj) = 46 同Metadata: ObjectId
- m_indexId (AllocUnitId.idInd) = 256 同Metadata: IndexId
- Metadata: AllocUnitId = 72057594040942592 存储单元的ID,sys.allocation_units.allocation_unit_id
- Metadata: PartitionId = 72057594039304192 数据页所在的分区号,sys.partitions.partition_id
- Metadata: IndexId = 0 页面的索引号,sys.objects.object_id&sys.indexes.index_id
- Metadata: ObjectId = 277576027 该页面所属的对象的id,sys.objects.object_id
- m_prevPage = (0:0) 该数据页的前一页面地址;主要用在数据页、索引页和IAM页
- m_nextPage = (0:0) 该数据页的后一页面地址;主要用在数据页、索引页和IAM页
- pminlen = 221 定长数据所占的字节数
- m_slotCnt = 2 页面中的数据的行数
- m_freeCnt = 7644 页面中剩余的空间(包括已删除记录所占空间)
- m_freeData = 544 数据部分和偏移量列表之间的空闲空间起始位置
- m_reservedCnt = 0 被活动事务保留的字节数,以便回滚事务
- m_lsn = (255:8406:2) 修改该页内数据的最后一个操作产生的lsn号
- m_xactReserved = 0 最新加入到m_reservedCnt上的字节数
- m_xdesId = (0:0) 添加到m_reservedCnt的最近的事务id
- m_ghostRecCnt = 0 幻影数据的行数
- m_tornBits = 0 页的校验位或者被由数据库页面保护形式决定分页保护位取代
再来看下页面相关分配情况:
- GAM (1:2) = ALLOCATED 在GAM页上的分配情况
- SGAM (1:3) = ALLOCATED 在SGAM页上的分配情况
- PFS (1:1) = 0x61 MIXED_EXT ALLOCATED 50_PCT_FULL 在PFS页上的分配情况,该页为50%满,
- DIFF (1:6) = CHANGED
- ML (1:7) = NOT MIN_LOGGED
接下来就是用于存放实际数据的槽(slot),每条记录存放一个槽(slot)里。0号槽在页里拥有第1条数据,1号槽拥有第2条数据,以此类推。通过下面的图片,你可以看到我们记录大小是224 bytes,217 bytes(50+50+100+5+4+8) 的定长和7 bytes 的系统行开销。
页的最后一部分是行偏移数组表,我们可以用参数为1的DBCC PAGE命令来看,在输出信息的底部获得。
DBCC TRACEON(3604)
DBCC PAGE(InternalStorageFormat,1,79,1)
GO
SQL Server在输出信息的底部,给我们如下的信息:
这个行偏移表,应该从下往上读。每条槽条目是一个2 bytes长的指针指向页里槽偏移量。这里我们插入了2条记录,所以表里有2个槽条目。第1条记录指向第96 bytes,刚好在页头后。这个行偏移表可以帮助我们管理页面的记录。在页里的行偏移表里,每条记录需要2 bytes的大小来存储。类似在堆表上建立的非聚集索引,每个非聚集索引行里都包含一个物理指针映射回堆表里的行记录。这个物理指针是[文件号:页号:槽号](file:page:solt)的结构,因此在读取页的时候,可以找到堆表里的对应行,再通过行偏移表里槽号里的偏移量,就可以在页里读取到对应的行记录。如果我们要修改页中间的记录,我们并不一定需要重组整个页,我们只要修改偏移表里偏移量即可。
在页头我们看到当前页面还有7644 bytes可以用,我们一起来验证下。
(8 * 1024) - 96 - (217 * 2)-(7 * 2)-(2 * 2)=7644 bytes
8 * 1024 = 页的总大小,8K
96 = 页头大小 96 bytes
217 * 2 = 每条记录的总长 * 记录数
7 * 2 = 每条记录的系统行开销 * 记录数
2 * 2 = 行偏移表里每槽占用字节数 * 记录数
- DBCC FILEHEADER
查看数据文件文件头数据
dbcc fileheader [( {'dbname' | dbid} [, fileid])
完整字段如下:
RecoveryUnitId | 0 |
FileId | 1 |
LogicalName | Image ©sqlity.net 2014 |
BindingId | 60371E59-22B9-412F-835C-8B88B1173F07 |
FileGroup | 1 |
Size | 7688 |
MaxSize | -1 |
MinSize | 392 |
UserShrinkSize | -1 |
Growth | 128 |
BackupLSN | 0 |
RedoStartLSN | 0 |
FirstLSN | 0 |
MaxLSN | 0 |
FirstUpdateLSN | 0 |
CreateLSN | 0 |
SectorSize | 512 |
ActualSectorSize | 512 |
RecoveryForkGUID | 00000000-0000-0000-0000-000000000000 |
RecoveryForkLSN | 0 |
DifferentialBaseLsn | 285000000204700037 |
DifferentialBaseGuid | 9C180429-584D-4F07-B5C4-9FB47480147D |
Status | 2 |
RestoreStatus | 0 |
ReadOnlyLsn | 0 |
ReadWriteLsn | 0 |
MaxLsnBranchId | 00000000-0000-0000-0000-000000000000 |
RedoTargetPointLsn | 0 |
RedoTargetPointGuid | 00000000-0000-0000-0000-000000000000 |
RestoreDiffBaseLsn | 0 |
RestoreDiffBaseGuid | 00000000-0000-0000-0000-000000000000 |
RestorePathOriginLsn | 0 |
RestorePathOriginGuid | 00000000-0000-0000-0000-000000000000 |
OldestRestoredLsn | 0 |
https://sqlity.net/en/2414/dbcc-fileheader/
- DBCC DBINFO
查看数据库启动页中信息
DBCC TRACEON(3604)
dbcc DBINFO [('dbname')]
输出如下:
DBINFO STRUCTURE:
DBINFO @0x0000000523D4D7F0
dbi_version = 869 dbi_createVersion = 869 dbi_SEVersion = 0
dbi_dvSplitPoint = 0:0:0 (0x00000000:00000000:0000)
dbi_dbbackupLSN = 0:0:0 (0x00000000:00000000:0000)
dbi_LastLogBackupTime = 1900-01-01 00:00:00.000
dbi_nextseqnum = 1900-01-01 00:00:00.000 dbi_status = 0x00910000
dbi_crdate = 2018-12-12 19:37:36.263dbi_dbname = hammerdb dbi_dbid = 6
dbi_cmptlevel = 140 dbi_masterfixups = 0 dbi_maxDbTimestamp = 2000
dbi_dbbackupLSN = 0:0:0 (0x00000000:00000000:0000) dbi_RebuildLogs = 0
dbi_differentialBaseLSN = 0:0:0 (0x00000000:00000000:0000) dbi_RestoreFlags = 0x0000
dbi_checkptLSN = 1301:23152:2 (0x00000515:00005a70:0002) dbi_dbccFlags = 2
dbi_COWLastLSN = 0:0:0 (0x00000000:00000000:0000)
dbi_DirtyPageLSN = 1301:23152:2 (0x00000515:00005a70:0002) dbi_RecoveryFlags = 0x00000000
dbi_lastxact = 0x50a769 dbi_collation = 53284 dbi_relstat = 0x61000000
dbi_PartitionDbFlags = 0 dbi_familyGUID = ff481ae4-5b17-4d5a-a737-a7ea11b65fbb
dbi_maxLogSpaceUsed = 612675584
dbi_recoveryForkNameStack
entry 0
hex (dec) = 0x00000000:00000000:0000 (0:0:0)
m_guid = ff481ae4-5b17-4d5a-a737-a7ea11b65fbb
entry 1
hex (dec) = 0x00000000:00000000:0000 (0:0:0)
m_guid = 00000000-0000-0000-0000-000000000000
dbi_differentialBaseGuid = 00000000-0000-0000-0000-000000000000 dbi_firstSysIndexes = 0001:00000014
dbi_oldestBackupXactLSN = 0:0:0 (0x00000000:00000000:0000)
dbi_versionChangeLSN = 0:0:0 (0x00000000:00000000:0000) dbi_mdUpgStat = 0x0004
dbi_category = 0x0000000000000000 dbi_safetySequence = 0
dbi_dbMirrorId = 00000000-0000-0000-0000-000000000000
dbi_pageUndoLsn = 0:0:0 (0x00000000:00000000:0000) dbi_pageUndoState = 0
dbi_disabledSequence = 0 dbi_dbmRedoLsn = 0:0:0 (0x00000000:00000000:0000)
dbi_dbmOldestXactLsn = 0:0:0 (0x00000000:00000000:0000) dbi_CloneCpuCount = 0
dbi_CloneMemorySize = 0 dbi_updSysCatalog = 1900-01-01 00:00:00.000
dbi_LogBackupChainOrigin = 0:0:0 (0x00000000:00000000:0000)
dbi_dbccLastKnownGood = 1900-01-01 00:00:00.000 dbi_roleSequence = 0
dbi_dbmHardenedLsn = 0:0:0 (0x00000000:00000000:0000) dbi_localState = 0
dbi_safety = 0 dbi_modDate = 2018-12-12 19:37:36.263
dbi_verRDB = 234884061 dbi_delayedDurabilityOption = 0
dbi_svcBrokerGUID = 8c856d11-5d59-47d1-90eb-b15a01d1ee5d dbi_svcBrokerOptions = 0x00000001
dbi_dbmLogZeroOutstanding = 0 dbi_dbmLastGoodRoleSequence = 0 dbi_dbmRedoQueue = 0
dbi_dbmRedoQueueType = 0 dbi_rmidRegistryValueDeleted = 0 dbi_dbmConnectionTimeout = 0
dbi_AuIdNext = 1099511627968 dbi_MinSkipLsn = 0:0:0 (0x00000000:00000000:0000)
dbi_commitTsOfcheckptLSN = 0 dbi_dbEmptyVersionState = 0 dbi_CurrentGeneration = 0
dbi_EncryptionHistory
Scan 0
hex (dec) = 0x00000000:00000000:0000 (0:0:0)
EncryptionScanInfo:ScanId = 0
Scan 1
hex (dec) = 0x00000000:00000000:0000 (0:0:0)
EncryptionScanInfo:ScanId = 0
Scan 2
hex (dec) = 0x00000000:00000000:0000 (0:0:0)
EncryptionScanInfo:ScanId = 0
dbi_latestVersioningUpgradeLSN = 18:61:69 (0x00000012:0000003d:0045)
dbi_PendingRestoreOutcomesId = 00000000-0000-0000-0000-000000000000 dbi_ContainmentState = 0
dbi_hkRecoveryLSN = 0:0:0 (0x00000000:00000000:0000)
dbi_hkLogTruncationLSN = 0:0:0 (0x00000000:00000000:0000) dbi_hkCompatibilityMode = 0
dbi_hkRootFile = 00000000-0000-0000-0000-000000000000 dbi_hkRootFileWatermark = 0
dbi_hkTrimLSN = 0:0:0 (0x00000000:00000000:0000)
dbi_hkUpgradeLSN = 0:0:0 (0x00000000:00000000:0000)
dbi_hkUndeployLSN = 0:0:0 (0x00000000:00000000:0000) dbi_heapPvsRowsetId = 0
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
参考
《sqlserver 2008 数据库技术内幕》