翻译如何计算分配单元ID?
翻译如何计算分配单元ID?
原文:allocation unit IDs calculated?
原文地址:Inside the Storage Engine: How are allocation unit IDs calculated?
正文:
自上一篇关于纯内幕的博文已经有很长一段时间了。很多人常常问我如何从页头部存储的m_objid和m_indexId计算出分配单元ID.
当使用DBCC PAGE列出页头部的内容时,确实先需要计算,然后根据元数据(metadata)找出分配单元id(allocation unit id)、分区ID(partition id)、相关对象和索引ID。基本上,通过DBCC PAGE输出的以Metadata: 前缀的数据都没有保存在页头部(译注:即都是通过计算和查找出来的):
计算公式如下:
- 将m_indexId左移48位,赋值给A
- 将m_objId左移16位,赋值给B
- AllocUnitId = A | B,这里的|是OR运算。
使用上面显示的页:
- A = 256 << 48 = 72057594037927936
- B = 97 << 16 = 6356992
- AllocUnitId = 72057594044284928
你可以使用SQL SERVER的POWER函数作为左移X位——就像乘以2的幂:
SELECT 256 * CONVERT (BIGINT, POWER (2.0, 48)) | 97 * CONVERT (BIGINT, POWER (2.0, 16)); GO
|
然后你就可以使用sys.system_internals_allocation_units和sys.partitions来进行各种查询了:
SELECT [a].[container_id] AS [Partition ID], [p].[object_id] AS [Object ID], [p].[index_id] AS [Index ID] FROM sys.system_internals_allocation_units [a] JOIN sys.partitions [p] ON [p].[partition_id] = [a].[container_id] WHERE [a].[allocation_unit_id] = 72057594044284928; GO
Partition ID Object ID Index ID -------------------- ----------- ----------- 72057594039304192 599673184 0
|
上面的输出和DBCC PAGE输出是一模一样的。
下面将分配单元ID再转换成你在DBCC PAGE输出中看到的:
- m_indexId = AllocUnitId >> 48
- m_objId = (AllocUnitId – (m_indexId << 48)) >> 16
因为要用到POWER的倒数,所以下面的这个T-SQL包含有浮点数:
DECLARE @alloc BIGINT = 72057594044284928; DECLARE @index BIGINT;
SELECT @index = CONVERT (BIGINT, CONVERT (FLOAT, @alloc) * (1 / POWER (2.0, 48)) -- right shift, reciprocal of left shift ); SELECT CONVERT (BIGINT, CONVERT (FLOAT, @alloc - (@index * CONVERT (BIGINT, POWER (2.0, 48)))) * (1 / POWER (2.0, 16)) -- right shift, reciprocal of left shift ) AS [m_objId], @index AS [m_indexId]; GO
m_objId m_indexId -------------------- -------------------- 97 256
|
一般用到上面这些代码的情形是:当编写程序来分析一个已经损坏了的数据库——该数据库已经不能DBCC CHECKDB来分析了。这时候,上面的这些代码可能是你的最后一根救命稻草。