FIRST
old_id
คุณอาจไม่จำเป็นต้องทั้งหมดสามคอลัมน์: external_id
, new_id
, new_id
คอลัมน์เป็นจะมีค่าใหม่ที่สร้างขึ้นสำหรับแต่ละแถวแม้เมื่อคุณใส่ลงในIDENTITY
external_id
แต่ระหว่างold_id
และexternal_id
เหล่านี้จะสวยมากพิเศษร่วมกันอย่างใดอย่างหนึ่งที่มีอยู่แล้วold_id
คุ้มค่าหรือคอลัมน์ว่าในความคิดในปัจจุบันจะเป็นเพียงNULL
ถ้าใช้หรือexternal_id
new_id
เนื่องจากคุณจะไม่เพิ่ม id "ภายนอก" ใหม่ลงในแถวที่มีอยู่แล้ว (เช่นที่มีold_id
ค่า) และจะไม่มีค่าใหม่เข้ามาold_id
ดังนั้นอาจมีหนึ่งคอลัมน์ที่ใช้ เพื่อวัตถุประสงค์ทั้งสอง
ดังนั้นกำจัดexternal_id
คอลัมน์และเปลี่ยนชื่อold_id
เป็นอะไรold_or_external_id
หรืออะไรก็ตาม สิ่งนี้ไม่จำเป็นต้องมีการเปลี่ยนแปลงที่แท้จริงกับสิ่งใด แต่ลดความยุ่งยากบางอย่าง อย่างมากคุณอาจต้องเรียกคอลัมน์external_id
แม้ว่าจะมีค่า "เก่า" หากโค้ดแอปถูกเขียนเพื่อแทรกเข้าไปexternal_id
แล้ว
ที่ช่วยลดโครงสร้างใหม่ให้เป็นเพียง:
PkId AS AS COALESCE(old_or_external_id, new_id, -1) PERSISTED NOT NULL,
old_or_external_id INT NULL, -- values from existing record OR passed in from app
new_id INT IDENTITY(2000000, 1) NOT NULL
ตอนนี้คุณเพิ่ม 8 ไบต์ต่อแถวแทนที่จะเป็น 12 ไบต์เท่านั้น (สมมติว่าคุณไม่ได้ใช้SPARSE
ตัวเลือกหรือการบีบอัดข้อมูล) และคุณไม่จำเป็นต้องเปลี่ยนรหัสใด ๆ T-SQL หรือรหัสแอป
SECOND
ต่อไปตามเส้นทางของการทำให้เข้าใจง่ายนี้เรามาดูสิ่งที่เราได้จากไป:
- คอลัมน์ทั้งมีค่าแล้วหรือจะได้รับค่าใหม่จากแอปหรือจะเหลือเป็น
old_or_external_id
NULL
new_id
มักจะมีค่าใหม่ที่สร้างขึ้น แต่ค่าที่จะใช้เฉพาะในกรณีที่คอลัมน์old_or_external_id
NULL
ไม่เคยมีช่วงเวลาที่คุณจะต้องค่าทั้งในและold_or_external_id
new_id
ใช่จะมีบางครั้งที่คอลัมน์ทั้งสองมีค่าเนื่องจากnew_id
การเป็นIDENTITY
แต่new_id
ค่าเหล่านั้นจะถูกละเว้น อีกครั้งฟิลด์สองฟิลด์นี้ไม่เหมือนกัน แล้วตอนนี้ล่ะ?
ตอนนี้เราสามารถดูว่าทำไมเราต้องการexternal_id
ในครั้งแรก เมื่อพิจารณาว่ามีความเป็นไปได้ที่จะแทรกลงในIDENTITY
คอลัมน์โดยใช้SET IDENTITY_INSERT {table_name} ON;
คุณสามารถหนีไปได้โดยไม่ต้องเปลี่ยนแปลงสคีมาเลยและเพียงแค่ปรับเปลี่ยนรหัสแอพของคุณเพื่อห่อINSERT
งบ / การดำเนินการSET IDENTITY_INSERT {table_name} ON;
และSET IDENTITY_INSERT {table_name} OFF;
คำสั่ง จากนั้นคุณต้องกำหนดช่วงเริ่มต้นในการรีเซ็ตIDENTITY
คอลัมน์เป็น (สำหรับค่าที่สร้างขึ้นใหม่) เนื่องจากจะต้องมีค่าสูงกว่าค่าที่รหัสแอปจะแทรกเนื่องจากการใส่ค่าที่สูงกว่าจะทำให้ค่าที่สร้างขึ้นอัตโนมัติถัดไปเป็น จะมากกว่าค่า MAX ปัจจุบัน แต่คุณสามารถแทรกค่าที่ต่ำกว่าค่าIDENT_CURRENTได้เสมอ
การรวมคอลัมน์old_or_external_id
และnew_id
ยังไม่เพิ่มโอกาสในการทำงานในสถานการณ์ค่าที่ทับซ้อนกันระหว่างค่าที่สร้างขึ้นอัตโนมัติและค่าที่สร้างโดยแอพเนื่องจากความตั้งใจที่จะมีคอลัมน์ 2 หรือ 3 คอลัมน์คือการรวมเข้ากับค่าคีย์หลัก และนั่นคือค่าที่ไม่ซ้ำกันเสมอ
ในวิธีการนี้คุณเพียงแค่ต้อง:
วินาทีส่วน B
รูปแบบเกี่ยวกับวิธีการที่ระบุไว้ข้างต้นโดยตรงคือการให้ค่าการแทรกรหัสแอปเริ่มต้นด้วย -1 และลงไปจากที่นั่น สิ่งนี้ทำให้IDENTITY
ค่าเป็นเพียงคนเดียวที่ขึ้นไป ประโยชน์ที่นี่คือคุณไม่เพียง แต่ไม่ทำให้คีมายุ่ง แต่คุณไม่ต้องกังวลเกี่ยวกับการทำงานใน ID ที่ทับซ้อนกัน (หากค่าที่สร้างโดยแอพทำงานในช่วงที่สร้างโดยอัตโนมัติใหม่) นี่เป็นเพียงตัวเลือกหากคุณยังไม่ได้ใช้ค่า ID เชิงลบ (และดูเหมือนว่าเป็นเรื่องยากที่ผู้ใช้จะใช้ค่าลบในคอลัมน์ที่สร้างขึ้นอัตโนมัติดังนั้นสิ่งนี้น่าจะเป็นไปได้ในสถานการณ์ส่วนใหญ่)
ในวิธีการนี้คุณเพียงแค่ต้อง:
ที่นี่คุณยังคงต้องทำIDENTITY_INSERT
แต่: คุณไม่ต้องเพิ่มคอลัมน์ใหม่ไม่จำเป็นต้อง "ทำการใหม่" IDENTITY
คอลัมน์ใด ๆและไม่มีความเสี่ยงในการทับซ้อนในอนาคต
วินาทีส่วนที่ 3
หนึ่งรูปแบบที่ผ่านมาของวิธีการนี้จะมีการแลกเปลี่ยนอาจจะออกIDENTITY
คอลัมน์และแทนที่จะใช้ลำดับ เหตุผลที่จะใช้วิธีการนี้คือการสามารถที่จะมีรหัสแอปแทรกค่าที่: บวกสูงกว่าช่วงที่สร้างขึ้นโดยอัตโนมัติ (ไม่ต่ำกว่า) SET IDENTITY_INSERT ON / OFF
และไม่จำเป็นต้องให้
ในวิธีการนี้คุณเพียงแค่ต้อง:
- สร้างลำดับโดยใช้CREATE SEQUENCE
คัดลอกIDENTITY
คอลัมน์ไปยังคอลัมน์ใหม่ที่ไม่มีIDENTITY
คุณสมบัติ แต่มีDEFAULT
ข้อ จำกัด โดยใช้ฟังก์ชันNEXT VALUE FOR
PkId INT PRIMARY KEY CONSTRAINT [DF_TableName_NextID] DEFAULT (NEXT VALUE FOR...)
สิ่งนี้เพิ่ม 0 ไบต์ให้กับแต่ละแถวแทนที่จะเป็น 8 หรือแม้กระทั่ง 12
- ช่วงเริ่มต้นสำหรับค่าที่สร้างขึ้นจากแอปจะดีกว่าสิ่งที่คุณคิดว่าค่าที่สร้างขึ้นโดยอัตโนมัติจะเข้าใกล้
- ใส่รหัสแอป INSERTs ใน
SET IDENTITY_INSERT {table_name} ON;
และSET IDENTITY_INSERT {table_name} OFF;
ข้อความสั่ง
อย่างไรก็ตามเนื่องจากความต้องการของรหัสที่มีอย่างใดอย่างหนึ่งSCOPE_IDENTITY()
หรือ@@IDENTITY
ยังคงทำงานอย่างถูกต้องสลับไปยังลำดับที่ไม่ได้เป็นตัวเลือกในขณะที่ปรากฏว่าไม่มีฟังก์ชั่นเหล่านั้นเทียบเท่าสำหรับลำดับ :-( เสียใจ!