Ходит популярное мнение, что если включить моментальные снимки (snapshot isolation), а затем перестроить индексы, то все строки таблицы получат дополнительные 14-байтовые теги версионирования. Правда это или миф? Давайте проверим.
Сначала я создам тестовую базу данных с небольшой таблицей, кластерным индексом и несколькими строками:
CREATE DATABASE SItest;
GO
USE SItest;
GO
CREATE TABLE SmallTable (c1 INT, c2 INT);CREATE CLUSTERED INDEX SmallTableCI ON SmallTable (c1);
GO
INSERT INTO SmallTable VALUES (1, 1);INSERT INTO SmallTable VALUES (2,2);
GO
Далее я включу READ_COMMITTED_SNAPSHOT и перестрою индекс, чтобы проверить, сработает ли версионирование на уровне выражения:
ALTER DATABASE SItest SET READ_COMMITTED_SNAPSHOT ON;
GO
ALTER INDEX SmallTableCI ON SmallTable REBUILD;
GO
Теперь посмотрим на страницу данных, где лежат две записи, чтобы выяснить, есть ли какие-либо сведения о версионировании (вывод немного укорочен для краткости):
DBCC IND (SItest, SmallTable, 1);
GO
DBCC TRACEON (3604); — remember this makes the output go to the consoleDBCC PAGE (SItest, 1, 153, 3);
GO
PageFID PagePID IAMFID IAMPID ObjectID IndexID
——- ———– —— ———– ———– ———–
1 154 NULL NULL 2073058421 1
1 153 1 154 2073058421 1
(2 row(s) affected)
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
PAGE: (1:153)
<SNIP SNIP SNIP>
Slot 0 Offset 0x60 Length 15
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Memory Dump @0x6209C060
00000000: 10000c00 01000000 01000000 0300f9 ……………
UNIQUIFIER = [NULL]
Slot 0 Column 1 Offset 0x4 Length 4
c1 = 1
Slot 0 Column 2 Offset 0x8 Length 4
c2 = 1
Slot 1 Offset 0x6f Length 15
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Memory Dump @0x6209C06F
00000000: 10000c00 02000000 02000000 0300f9 ……………
UNIQUIFIER = [NULL]
Slot 1 Column 1 Offset 0x4 Length 4
c1 = 2
Slot 1 Column 2 Offset 0x8 Length 4
c2 = 2
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Нет — обе записи выглядят обычно. Для полноты картины попробуем версионирование на уровне транзакции и затем перестроение:
ALTER DATABASE SItest SET ALLOW_SNAPSHOT_ISOLATION ON;
GO
ALTER INDEX SmallTableCI ON SmallTable REBUILD;
GO
DBCC IND (SItest, SmallTable, 1);
GO
DBCC PAGE (SItest, 1, 143, 3); — page changed when we rebuilt the indexGO
PageFID PagePID IAMFID IAMPID ObjectID IndexID
——- ———– —— ———– ———– ———–
1 152 NULL NULL 2073058421 1
1 143 1 152 2073058421 1
(2 row(s) affected)
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
PAGE: (1:143)
<SNIP SNIP SNIP>
Slot 0 Offset 0x60 Length 15
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Memory Dump @0x6209C060
00000000: 10000c00 01000000 01000000 0300f9 ……………
UNIQUIFIER = [NULL]
Slot 0 Column 1 Offset 0x4 Length 4
c1 = 1
Slot 0 Column 2 Offset 0x8 Length 4
c2 = 1
Slot 1 Offset 0x6f Length 15
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP
Memory Dump @0x6209C06F
00000000: 10000c00 02000000 02000000 0300f9 ……………
UNIQUIFIER = [NULL]
Slot 1 Column 1 Offset 0x4 Length 4
c1 = 2
Slot 1 Column 2 Offset 0x8 Length 4
c2 = 2
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Снова нет — ничего. Теперь я принудительно спровоцирую операцию версионирования, и мы должны увидеть теги. Любое обновление таблицы приводит к созданию версионированных записей. В данном случае я начну явную транзакцию и выполню несколько обновлений, а исходные значения посмотрим из другого окна запроса. Сначала — обновления:
BEGIN TRAN;
GO
UPDATE SmallTable SET c1 = 4;
GO
А в другом окне:
SELECT * FROM smalltable;
GO
c1 c2
———– ———–
1 1
2 2
(2 row(s) affected)
Отлично — исходные значения по‑прежнему видны. Посмотрим сведения о версионировании на странице данных (вывод снова укорочен):
DBCC PAGE (SItest, 1, 143, 3);
GO
PAGE: (1:143)
<SNIP SNIP SNIP>
Slot 0 Offset 0x7e Length 29
Record Type = GHOST_DATA_RECORD Record Attributes = NULL_BITMAP VERSIONING_INFO
Memory Dump @0x61CEC07E
00000000: 5c000c00 01000000 01000000 0300f9e0 \……………
00000010: 00000001 00000057 03000000 00 …….W…..
**Version Infomation =
Transaction Timestamp: 855
Version Pointer: (file 1 page 224 slot 0)**
UNIQUIFIER = [NULL]
Slot 0 Column 1 Offset 0x4 Length 4
c1 = 1
Slot 0 Column 2 Offset 0x8 Length 4
c2 = 1
Slot 1 Offset 0xb8 Length 29
Record Type = GHOST_DATA_RECORD Record Attributes = NULL_BITMAP **VERSIONING_INFO**
Memory Dump @0x61CEC0B8
00000000: 5c000c00 02000000 02000000 0300f9e0 \……………
00000010: 00000001 00010057 03000000 00 …….W…..
**Version Infomation =
Transaction Timestamp: 855
Version Pointer: (file 1 page 224 slot 1)**
UNIQUIFIER = [NULL]
Slot 1 Column 1 Offset 0x4 Length 4
c1 = 2
Slot 1 Column 2 Offset 0x8 Length 4
c2 = 2
Slot 2 Offset 0x9b Length 29
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VERSIONING_INFO
Memory Dump @0x61CEC09B
00000000: 50000c00 04000000 01000000 0300f800 P……………
00000010: 00000000 00000057 03000000 00 …….W…..
Version Information =
Transaction Timestamp: 855
Version Pointer: Null
UNIQUIFIER = [NULL]
Slot 2 Column 1 Offset 0x4 Length 4
c1 = 4
Slot 2 Column 2 Offset 0x8 Length 4
c2 = 1
Slot 3 Offset 0xd5 Length 37
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS VERSIONING_INFO
Memory Dump @0x61CEC0D5
00000000: 70000c00 04000000 02000000 0300f801 p……………
00000010: 00170001 00000000 00000000 00000057 ……………W
00000020: 03000000 00 …..
Version Information =
Transaction Timestamp: 855
Version Pointer: Null
Slot 3 Column 0 Offset 0x13 Length 4
UNIQUIFIER = 1
Slot 3 Column 1 Offset 0x4 Length 4
c1 = 4
Slot 3 Column 2 Offset 0x8 Length 4
c2 = 2
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Я выделил части, относящиеся к версионированию, полужирным. Обратите внимание, что старые записи тоже превратились в фантомные (ghost). Вторая запись теперь помечена как имеющая столбцы переменной длины. Это потому, что я обновил обе записи до одного и того же значения кластерного ключа, и второй записи теперь требуется «уникализатор» (uniquifier) — он хранится как столбец переменной длины.
Итак, исходное утверждение — миф: строки получают сведения о версионировании только тогда, когда это действительно нужно для поддержки операции версионирования.
Комментариев нет:
Отправить комментарий