เปลี่ยนคอลัมน์ NULL อย่างรวดเร็วเป็น NOT NULL


11

ฉันมีตารางที่มีแถวเป็นล้านแถวและคอลัมน์ที่อนุญาตให้มีค่า NULL อย่างไรก็ตามในขณะนี้ไม่มีแถวที่มีค่า NULL สำหรับคอลัมน์นั้น (ฉันสามารถตรวจสอบได้อย่างรวดเร็วด้วยแบบสอบถาม) อย่างไรก็ตามเมื่อฉันรันคำสั่ง

ALTER TABLE MyTable ALTER COLUMN MyColumn BIGINT NOT NULL;

แบบสอบถามใช้เวลาพูดค่อนข้างตลอดไป ใช้เวลาประมาณ 10 ถึง 20 นาทีซึ่งนานกว่าสองเท่าของการเพิ่มข้อ จำกัด การตรวจสอบ มีวิธีอัปเดตข้อมูลเมตาของตารางสำหรับคอลัมน์นั้นทันทีโดยเฉพาะเมื่อฉันรู้ว่าไม่มีแถวใดที่มีค่า NULL สำหรับคอลัมน์นั้น


2
ไม่ (หรืออย่างน้อยไม่ใช้วิธีการที่เป็นเอกสาร / สนับสนุน) ดูเหตุใดการเปลี่ยนคอลัมน์เป็นไม่เป็นศูนย์ทำให้เกิดการเติบโตของไฟล์บันทึกขนาดใหญ่
Martin Smith

2
มันอาจเป็นไปได้ที่จะรอการSch-Mล็อคเมื่อมัน "ตลอดไป" คุณดูเพื่อดูว่ามันกำลังรอหรือไม่ว่าง?
Martin Smith

@MartinSmith ผมชี้แจงว่าผมหมายถึงโดยตลอด ฉันกำลังทดสอบสิ่งนี้ในสภาพแวดล้อมการพัฒนาโดยไม่มีเซสชันอื่นที่กระทบฐานข้อมูล มันจะเสร็จสมบูรณ์ในที่สุด แต่คำตอบที่คุณเชื่อมโยงนั้นอธิบายว่าทำไมมันใช้เวลานาน หากคุณสามารถใส่ความคิดเห็นของคุณเป็นคำตอบได้ฉันจะยอมรับมัน
โจเซฟไดเกิล

คำตอบ:


12

คำตอบของ @ ypercubeจัดการบางส่วนนี้เนื่องจากข้อมูลเมตามีการเปลี่ยนแปลงเท่านั้น

การเพิ่มข้อ จำกัด ด้วยNOCHECKวิธีที่ไม่จำเป็นต้องอ่านแถวเพื่อยืนยันและถ้าคุณเริ่มจากตำแหน่งที่คอลัมน์ไม่มีNULLค่า (และถ้าคุณรู้ว่าไม่มีใครจะถูกเพิ่มระหว่างการตรวจสอบและเพิ่มข้อ จำกัด ) เนื่องจากข้อ จำกัด จะป้องกันNULLค่าที่ถูกสร้างขึ้นจากอนาคตINSERTหรือUPDATEการดำเนินการสิ่งนี้จะได้ผล

อย่างไรก็ตามการเพิ่มข้อ จำกัด ยังคงมีผลกระทบต่อการทำธุรกรรมพร้อมกัน ALTER TABLEจะต้องได้รับSch-Mล็อคแรก ในขณะที่มันกำลังรอให้ทั้งหมดนี้เข้าถึงตารางอื่น ๆ จะถูกปิดกั้นตามที่อธิบายไว้ที่นี่

เมื่อSch-Mล็อคได้รับการดำเนินการควรจะค่อนข้างเร็วอย่างไรก็ตาม

ปัญหาอย่างหนึ่งของเรื่องนี้ก็คือแม้ว่าคุณจะรู้ว่าคอลัมน์ในความเป็นจริงไม่มีNULLข้อ จำกัด แต่ก็ไม่ได้รับความเชื่อถือจากตัวปรับแต่งข้อความค้นหาซึ่งหมายความว่าแผนสามารถย่อยได้ดีที่สุด

CREATE TABLE T (X INT NULL)

INSERT INTO T 
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM master..spt_values

ALTER TABLE T WITH NOCHECK
  ADD  CONSTRAINT X_NOT_NULL 
    CHECK (X IS NOT NULL) ; 

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

วางแผน

เปรียบเทียบสิ่งนี้กับสิ่งที่ง่ายกว่า

ALTER TABLE T ALTER COLUMN X INT NOT NULL

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

วางแผน

ปัญหาที่เป็นไปได้อย่างหนึ่งที่คุณอาจประสบกับการแก้ไขนิยามคอลัมน์ด้วยวิธีนี้คือไม่เพียง แต่ต้องอ่านแถวทั้งหมดเพื่อตรวจสอบว่าตรงตามเงื่อนไข แต่ยังสามารถจบลงด้วยการอัปเดตที่บันทึกไว้ในแถวจริง

WITH CHECKวิธีที่บ้านครึ่งหนึ่งที่เป็นไปได้อาจจะมีการเพิ่มข้อ จำกัด การตรวจสอบ สิ่งนี้จะช้ากว่าWITH NOCHECKที่ต้องอ่านทุกแถว แต่จะอนุญาตให้เครื่องมือเพิ่มประสิทธิภาพคิวรีให้แผนที่ง่ายขึ้นในแบบสอบถามด้านบนและควรหลีกเลี่ยงปัญหาการอัพเดตที่บันทึกไว้ที่เป็นไปได้


7

คุณสามารถเพิ่มCHECKข้อ จำกัด ของตารางด้วยNOCHECKตัวเลือกแทนการแก้ไขคอลัมน์ได้

ALTER TABLE MyTable WITH NOCHECK
  ADD  CONSTRAINT MyColumn_NOT_NULL 
    CHECK (MyColumn IS NOT NULL) ;

1
สิ่งนี้จะป้องกันการอัปเดตหรือส่วนแทรกในอนาคตที่สร้างคอลัมน์NULLแต่จะไม่สามารถใช้งานได้โดยเครื่องมือเพิ่มประสิทธิภาพคิวรี
Martin Smith

@MartinSmith โอ้ใช่ฉันเพิ่งอ่านคำตอบและความคิดเห็นในคำถามที่คล้ายกัน: คุณจะเพิ่มคอลัมน์ NOT NULL ให้กับตารางขนาดใหญ่ใน SQL Server ได้อย่างไร กรุณาเพิ่มคำตอบกับปัญหาหรือทางออกที่ดีกว่าและฉันจะลบของฉัน
ypercubeᵀᴹ

2
ฉันไม่มีทางออกที่ดีกว่า ฉันลงคะแนนเพราะนี่เป็นวิธีแก้ปัญหาบางส่วน หาก OP ต้องการทำทั้งหมดเป็นการป้องกันข้อมูลที่ไม่ถูกต้องมันจะทำงานได้ (และควรเร็วกว่าALTER COLUMNเมื่อได้รับการSch-Mล็อคนี่ไม่จำเป็นต้องสแกนแถวเลย) เพียงแค่ชี้ให้เห็นว่ามันไม่เหมือนกัน (เช่นหากใช้ในNOT INแบบสอบถามแผนจะซับซ้อนมากขึ้น)
Martin Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.