SQL Server 将表的 IDENTITY VALUE 物理存储在何处?

Sim*_*nes 12 sql-server database-internals identity sql-server-2014

我希望有人可以为我指出正确的方向。到目前为止,这是我的工作。

SELECT * FROM sys.identity_columns是一个系统视图,它给出了“last_value”,但该视图的定义使用了一个内部函数IdentityProperty(colName, 'LastValue')- 所以这是一个死胡同(不是从那里的系统表中提取它)。

互联网上的任何地方(我看过)都建议使用DBCC IDENT_...命令来揭示价值,但这仍然让我对它的实际存储位置一无所知。

因此,我开始DBCC PAGE(TestDB,1,1325,3)根据我的测试工具数据库搜索各个页面,并使用该RESEED命令在值 10 和 12 之间重新设定种子。

在这一过程中,我注意到的十六进制值IAM: HeaderIAM: Single Page Allocations并且IAM: Extent Alloc Status Slot 1一切都改变了。(并且意识到它们无论如何都会随着bUse1值定期更改,而bUse1值也会自行递增)。

所以另一个死胡同,我完全没有想法。我还能在哪里搜索?

我正在运行 SQL Server 2014。我对内部知识有着永不满足的渴望,但还没有遇到过像这样难以捉摸的东西。它引起了我的注意,因为从理论上讲,它(绝对值)存储在某处并且应该(可以说)是可定位的。在我寻找内部存储数据/元数据的位置的过程中,这个特殊的价值让我觉得特别难以捉摸。我猜/希望有人会过来告诉我,你可以得到它,DBCC PAGE但我找错了地方。

Han*_*non 8

如果您可以访问 DAC(专用管理员控制台),则可以INT通过查看 中的idtval列来检查标识列的值sys.syscolpars

感谢Martin Smith通过Roi Gavish对相关问题的这个非常有用的回答将我引导到该表。

以下面的临时表为例:

USE tempdb;

CREATE TABLE #d
(
    ID INT NOT NULL IDENTITY(1,1)
);

TRUNCATE TABLE #d;

DBCC CHECKIDENT ('#d',RESEED, 2147483635);

INSERT INTO #d DEFAULT VALUES;
Run Code Online (Sandbox Code Playgroud)

让我们看看表包含什么:

SELECT *
FROM #d;
Run Code Online (Sandbox Code Playgroud)
USE tempdb;

CREATE TABLE #d
(
    ID INT NOT NULL IDENTITY(1,1)
);

TRUNCATE TABLE #d;

DBCC CHECKIDENT ('#d',RESEED, 2147483635);

INSERT INTO #d DEFAULT VALUES;
Run Code Online (Sandbox Code Playgroud)

可以通过以下代码检查标识值:

DECLARE @idtval VARBINARY(64);

SELECT @idtval = scp.idtval
FROM sys.syscolpars scp
    INNER JOIN sys.objects o ON scp.id = o.object_id
WHERE o.name LIKE '#d____%'

DECLARE @LittleEndian NVARCHAR(10);
SET @LittleEndian = LEFT(sys.fn_varbintohexstr(@idtval), 10);
SELECT @LittleEndian;
DECLARE @BigEndian NVARCHAR(10) = '0x';
DECLARE @Loop INT = 0;
WHILE @Loop < 4
BEGIN
  SET @BigEndian = @BigEndian + SUBSTRING(@LittleEndian, ((4 - @Loop) * 2) + 1, 2);
  SET @Loop += 1;
END
SELECT CurrentIdentityValue = CONVERT(INT, 
    CONVERT(VARBINARY(32), @BigEndian, 1), 2);
Run Code Online (Sandbox Code Playgroud)
SELECT *
FROM #d;
Run Code Online (Sandbox Code Playgroud)

对于BIGINT标识列,我们需要扩大代码中用到的一些变量的大小,比如:

CREATE TABLE #dBig
(
    ID BIGINT NOT NULL IDENTITY(1,1)
);

TRUNCATE TABLE #dBig;

DBCC CHECKIDENT ('#dBig',RESEED, 9223372036854775704);

INSERT INTO #dBig DEFAULT VALUES;

SELECT *
FROM #dBig;


DECLARE @idtval VARBINARY(64);

SELECT @idtval = scp.idtval
FROM sys.syscolpars scp
    INNER JOIN sys.objects o ON scp.id = o.object_id
WHERE o.name LIKE '#dBig____%'

DECLARE @LittleEndian NVARCHAR(18);
SET @LittleEndian = LEFT(sys.fn_varbintohexstr(@idtval), 18);
DECLARE @BigEndian NVARCHAR(18) = '0x';
DECLARE @Loop INT = 0;
WHILE @Loop < 8
BEGIN
  SET @BigEndian = @BigEndian + SUBSTRING(@LittleEndian, ((8 - @Loop) * 2) + 1, 2);
  SET @Loop += 1;
END
SELECT CurrentIdentityValue = CONVERT(BIGINT, 
    CONVERT(VARBINARY(32), @BigEndian, 1), 2);
Run Code Online (Sandbox Code Playgroud)

结果BIGINT

+------------+
| ID         |
+------------+
| 2147483635 |
+------------+
Run Code Online (Sandbox Code Playgroud)