มีบางสถานการณ์ที่การวางคอลัมน์สามารถเป็นการดำเนินการกับเมตาดาต้า - ข้อมูลเท่านั้น คำจำกัดความของคอลัมน์สำหรับตารางที่กำหนดจะไม่รวมอยู่ในแต่ละหน้าและทุกแถวที่เก็บแถวคำจำกัดความของคอลัมน์จะถูกเก็บไว้ในข้อมูลเมตาของฐานข้อมูลเท่านั้นรวมถึง sys.sysrowsets, sys.sysrscols เป็นต้น
เมื่อวางคอลัมน์ที่ไม่ได้อ้างถึงโดยวัตถุอื่น ๆ เครื่องมือจัดเก็บข้อมูลจะทำเครื่องหมายคำจำกัดความของคอลัมน์ว่าไม่มีอยู่อีกต่อไปโดยการลบรายละเอียดที่เกี่ยวข้องจากตารางระบบต่างๆ การกระทำของการลบ meta-data จะทำให้โพรซีเดอร์แคชใช้ไม่ได้ซึ่งจำเป็นต้องมีการคอมไพล์ใหม่เมื่อใดก็ตามที่เคียวรีอ้างถึงตารางนั้นในภายหลัง ตั้งแต่ recompile เท่านั้นส่งกลับคอลัมน์ที่ขณะนี้อยู่ในตารางรายละเอียดคอลัมน์สำหรับคอลัมน์ลดลงจะไม่เคยถามแม้สำหรับ; เอ็นจิ้นการจัดเก็บข้ามไบต์ที่จัดเก็บในแต่ละหน้าของคอลัมน์นั้นราวกับว่าไม่มีคอลัมน์อยู่อีกต่อไป
เมื่อการดำเนินการ DML ที่ตามมาเกิดขึ้นกับตารางหน้าเว็บที่ได้รับผลกระทบจะถูกเขียนใหม่โดยไม่มีข้อมูลสำหรับคอลัมน์ที่ถูกดร็อป หากคุณสร้างดัชนีคลัสเตอร์หรือฮีปใหม่ไบต์ทั้งหมดสำหรับคอลัมน์ที่ถูกดร็อปจะไม่ถูกเขียนกลับไปที่หน้าบนดิสก์ตามธรรมชาติ สิ่งนี้จะกระจายโหลดของการปล่อยคอลัมน์อย่างมีประสิทธิภาพเมื่อเวลาผ่านไปทำให้สังเกตเห็นได้น้อยลง
มีสถานการณ์ที่คุณไม่สามารถวางคอลัมน์เช่นเมื่อคอลัมน์รวมอยู่ในดัชนีหรือเมื่อคุณสร้างวัตถุสถิติสำหรับคอลัมน์ด้วยตนเอง ฉันเขียนโพสต์บล็อกที่แสดงข้อผิดพลาดที่เกิดขึ้นเมื่อพยายามแก้ไขคอลัมน์ด้วยวัตถุสถิติที่สร้างขึ้นด้วยตนเอง ซีแมนทิกส์เดียวกันจะใช้เมื่อวางคอลัมน์ - หากมีการอ้างอิงคอลัมน์โดยวัตถุอื่นใดมันไม่สามารถทิ้งได้ ต้องอ้างอิงวัตถุการอ้างอิงก่อนจากนั้นจึงสามารถลบคอลัมน์ได้
นี่เป็นเรื่องง่ายที่จะแสดงโดยดูที่เนื้อหาของบันทึกการทำธุรกรรมหลังจากวางคอลัมน์ รหัสด้านล่างสร้างตารางที่มีคอลัมน์ถ่านยาว 8,000 รายการ มันเพิ่มแถวจากนั้นลดลงและแสดงเนื้อหาของบันทึกการทำธุรกรรมที่เกี่ยวข้องกับการดำเนินการปล่อย บันทึกข้อมูลแสดงการปรับเปลี่ยนตารางระบบต่างๆที่จัดเก็บคำจำกัดความของตารางและคอลัมน์ หากข้อมูลคอลัมน์ถูกลบจริงจากหน้าเว็บที่จัดสรรให้กับตารางคุณจะเห็นบันทึกบันทึกที่บันทึกข้อมูลหน้าจริง ไม่มีบันทึกดังกล่าว
DROP TABLE IF EXISTS dbo.DropColumnTest;
GO
CREATE TABLE dbo.DropColumnTest
(
rid int NOT NULL
CONSTRAINT DropColumnTest_pkc
PRIMARY KEY CLUSTERED
, someCol varchar(8000) NOT NULL
);
INSERT INTO dbo.DropColumnTest (rid, someCol)
SELECT 1, REPLICATE('Z', 8000);
GO
DECLARE @startLSN nvarchar(25);
SELECT TOP(1) @startLSN = dl.[Current LSN]
FROM sys.fn_dblog(NULL, NULL) dl
ORDER BY dl.[Current LSN] DESC;
DECLARE @a int = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), LEFT(@startLSN, 8), 0), 1)
, @b int = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), SUBSTRING(@startLSN, 10, 8), 0), 1)
, @c int = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), RIGHT(@startLSN, 4), 0), 1);
SELECT @startLSN = CONVERT(varchar(8), @a, 1)
+ ':' + CONVERT(varchar(8), @b, 1)
+ ':' + CONVERT(varchar(8), @c, 1)
ALTER TABLE dbo.DropColumnTest DROP COLUMN someCol;
SELECT *
FROM sys.fn_dblog(@startLSN, NULL)
--modify an existing data row
SELECT TOP(1) @startLSN = dl.[Current LSN]
FROM sys.fn_dblog(NULL, NULL) dl
ORDER BY dl.[Current LSN] DESC;
SET @a = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), LEFT(@startLSN, 8), 0), 1);
SET @b = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), SUBSTRING(@startLSN, 10, 8), 0), 1);
SET @c = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), RIGHT(@startLSN, 4), 0), 1);
SELECT @startLSN = CONVERT(varchar(8), @a, 1)
+ ':' + CONVERT(varchar(8), @b, 1)
+ ':' + CONVERT(varchar(8), @c, 1)
UPDATE dbo.DropColumnTest SET rid = 2;
SELECT *
FROM sys.fn_dblog(@startLSN, NULL)
(เอาต์พุตมีขนาดใหญ่เกินกว่าที่จะแสดงที่นี่และ dbfiddle.uk จะไม่อนุญาตให้ฉันเข้าถึง fn_dblog)
ชุดแรกของการส่งออกแสดงบันทึกเป็นผลมาจากคำสั่ง DDL วางคอลัมน์ ชุดที่สองของการส่งออกแสดงบันทึกหลังจากใช้คำสั่ง DML ที่เราปรับปรุงrid
คอลัมน์ ในชุดผลลัพธ์ที่สองเราจะเห็นบันทึกบันทึกแสดงการลบต่อ dbo.DropColumnTest ตามด้วยการแทรกลงใน dbo.DropColumnTest ความยาวของบันทึกแต่ละรายการคือ 8116 เพื่อระบุว่าหน้าจริงได้รับการอัพเดต
ดังที่คุณเห็นจากผลลัพธ์ของfn_dblog
คำสั่งในการทดสอบด้านบนการดำเนินการทั้งหมดถูกบันทึกอย่างสมบูรณ์ นี่เป็นการกู้คืนแบบง่ายเช่นเดียวกับการกู้คืนแบบเต็ม คำศัพท์ "ล็อกเต็มที่" อาจตีความผิดเนื่องจากการดัดแปลงข้อมูลไม่ถูกบันทึก นี่ไม่ใช่สิ่งที่เกิดขึ้น - การแก้ไขจะถูกบันทึกและสามารถย้อนกลับได้อย่างสมบูรณ์ บันทึกเป็นเพียงเพียงบันทึกหน้าเว็บที่ถูกสัมผัสและเนื่องจากไม่มีตารางข้อมูลหน้าถูกบันทึกไว้โดยการดำเนินการ DDL ทั้งDROP COLUMN
และย้อนกลับใด ๆ ที่อาจเกิดขึ้นจะเกิดขึ้นอย่างรวดเร็วมากโดยไม่คำนึงถึงขนาดของตาราง
สำหรับวิทยาศาสตร์รหัสต่อไปนี้จะถ่ายโอนข้อมูลหน้าสำหรับตารางที่รวมอยู่ในรหัสข้างต้นโดยใช้DBCC PAGE
สไตล์ "3" สไตล์ "3" หมายถึงเราต้องการให้ส่วนหัวของหน้าพร้อมการตีความต่อแถวอย่างละเอียด รหัสใช้เคอร์เซอร์เพื่อแสดงรายละเอียดสำหรับทุกหน้าในตารางดังนั้นคุณอาจต้องการตรวจสอบให้แน่ใจว่าคุณไม่ได้เรียกใช้สิ่งนี้ในตารางขนาดใหญ่
DBCC TRACEON(3604); --directs out from DBCC commands to the console, instead of the error log
DECLARE @dbid int = DB_ID();
DECLARE @fileid int;
DECLARE @pageid int;
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT dpa.allocated_page_file_id
, dpa.allocated_page_page_id
FROM sys.schemas s
INNER JOIN sys.objects o ON o.schema_id = s.schema_id
CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), o.object_id, NULL, NULL, 'DETAILED') dpa
WHERE o.name = N'DropColumnTest'
AND s.name = N'dbo'
AND dpa.page_type_desc = N'DATA_PAGE';
OPEN cur;
FETCH NEXT FROM cur INTO @fileid, @pageid;
WHILE @@FETCH_STATUS = 0
BEGIN
DBCC PAGE (@dbid, @fileid, @pageid, 3);
FETCH NEXT FROM cur INTO @fileid, @pageid;
END
CLOSE cur;
DEALLOCATE cur;
DBCC TRACEOFF(3604);
ดูผลลัพธ์สำหรับหน้าแรกจากการสาธิตของฉัน (หลังจากที่คอลัมน์ถูกดร็อป แต่ก่อนที่คอลัมน์จะถูกอัพเดต) ฉันเห็นสิ่งนี้:
หน้า: (1: 100104)
กันชน:
BUF @ 0x0000021793E42040
bpage = 0x000002175A7A0000 bhash = 0x00000000000000000000 bpageno = (1: 100104)
bdbid = 10 Breferences = 1 bcputicks = 0
bsampleCount = 0 bUse1 = 13760 bstat = 0x10b
บล็อก = 0x212121cc bnext = 0x00000000000000000000 bDirtyContext = 0x000002175004B640
bstat2 = 0x0
ส่วนหัวของหน้า:
หน้า @ 0x000002175A7A0000
m_pageId = (1: 100104) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0xc000
m_objId (AllocUnitId.idObj) = 300 m_indexId (AllocUnitId.idInd) = 256
ข้อมูลเมตา: AllocUnitId = 72057594057588736
ข้อมูลเมตา: พาร์ติชันรหัส = 72057594051756032 ข้อมูลเมตา: ดัชนีหมายเลข = 1
ข้อมูลเมตา: ObjectId = 174623665 m_prevPage = (0: 0) m_nextPage = (0: 0)
pminlen = 8 m_slotCnt = 1 m_freeCnt = 79
m_freeData = 8111 m_reservedCnt = 0 m_lsn = (616: 14191: 25)
m_xactReserved = 0 m_xdesId = (0: 0) m_ghostRecCnt = 0
m_tornBits = 0 DB Frag ID = 1
สถานะการจัดสรร
GAM (1: 2) = จัดสรร SGAM (1: 3) = ไม่จัดสรร
PFS (1: 97056) = 0x40 จัดสรร 0_PCT_FULL DIFF (1: 6) = เปลี่ยน
ML (1: 7) = ไม่ MIN_LOGGED
ช่อง 0 ออฟเซ็ต 0x60 ความยาว 8015
ประเภทระเบียน = Primary_RECORD คุณสมบัติบันทึก = NULL_BITMAP VARIABLE_COLUMNS
ขนาดบันทึก = 8015
Memory Dump @ 0x000000B75227A060
0000000000000000: 30000800 01000000 02000001 004f1f5a 5a5a5a5a 0 ............ O.ZZZZZ
0000000000000014: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZZZZZZ
.
.
.
0000000000001F2C: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZZZZZ
0000000000001F40: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a ZZZZZZZZZZZZZZZZZZ
ช่อง 0 คอลัมน์ 1 ชดเชย 0x4 ความยาว 4 ความยาว (ทางกายภาพ) 4
rid = 1
ช่อง 0 คอลัมน์ 67108865 ชดเชย 0xf ความยาว 0 ความยาว (ทางกายภาพ) 8000
DROPPED = NULL
ช่อง 0 ออฟเซ็ต 0x0 ความยาว 0 ความยาว (ทางกายภาพ) 0
KeyHashValue = (8194443284a0)
ฉันได้ลบทราฟฟิกหน้าส่วนใหญ่ออกจากผลลัพธ์ที่แสดงด้านบนเพื่อความกระชับ ในตอนท้ายของผลลัพธ์คุณจะเห็นสิ่งนี้สำหรับrid
คอลัมน์:
ช่อง 0 คอลัมน์ 1 ชดเชย 0x4 ความยาว 4 ความยาว (ทางกายภาพ) 4
rid = 1
บรรทัดสุดท้ายด้านบนrid = 1
ส่งคืนชื่อของคอลัมน์และค่าปัจจุบันที่เก็บไว้ในคอลัมน์ในหน้า
ถัดไปคุณจะเห็นสิ่งนี้:
ช่อง 0 คอลัมน์ 67108865 ชดเชย 0xf ความยาว 0 ความยาว (ทางกายภาพ) 8000
DROPPED = NULL
ผลลัพธ์แสดงให้เห็นว่า Slot 0 มีคอลัมน์ที่ถูกลบโดยอาศัยDELETED
ข้อความที่ปกติชื่อคอลัมน์จะเป็น ค่าของคอลัมน์ถูกส่งคืนNULL
เนื่องจากลบคอลัมน์แล้ว อย่างไรก็ตามตามที่คุณเห็นในข้อมูลดิบค่าความยาว 8,000 อักขระREPLICATE('Z', 8000)
สำหรับคอลัมน์นั้นยังคงมีอยู่บนหน้า นี่เป็นตัวอย่างของส่วนนั้นของเอาต์พุต DBAGE PAGE:
0000000000001EDC: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZZZZZ
0000000000001EF0: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZZZZZ
0000000000001F04: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZZZZZ
0000000000001F18: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZZZZZZ