เหตุผลในการหลีกเลี่ยงค่า ID ขนาดใหญ่


17

เรากำลังทำงานกับเว็บแอปพลิเคชันซึ่งผู้ใช้ยังไม่สามารถเข้าถึงได้ เจ้านายของฉันสังเกตเห็นว่าระเบียนที่สร้างขึ้นใหม่ได้รับ ID มากกว่า 10,000 รายการแม้ว่าเราจะมีระเบียนน้อยกว่า 100 รายการในตาราง เธอคิดว่าเว็บอินเตอร์เฟสด้วยเหตุผลบางอย่างสร้างเร็กคอร์ดชั่วคราวมากกว่า 100 เท่ามากกว่าเรคคอร์ดจริง (และลบทิ้ง) และสิ่งนี้สามารถนำเราให้วิ่งออกจากระยะภายในไม่กี่เดือนหลังจากปล่อย

ฉันไม่คิดว่าเธอถูกต้องเกี่ยวกับสาเหตุของ ID อัตราเงินเฟ้อ (เพื่อนร่วมงานที่สามารถตอบคำถามนี้ในวันหยุดดังนั้นเราไม่ทราบแน่นอน) แต่สมมติว่าเธอเป็น เธอบอกว่าเธอเกลียดที่จะใช้คอลัมน์ bigint และเธอต้องการให้เราหยุดการสร้างคอลัมน์ ID โดยอัตโนมัติและเขียนรหัสฝั่งเซิร์ฟเวอร์ซึ่งเลือกจำนวนเต็ม "ไม่ได้ใช้" แรกและใช้เป็น ID

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

อะไรคือข้อโต้แย้งสำหรับและต่อต้านแต่ละตำแหน่ง? มีอะไรที่ไม่ดีเกิดขึ้นได้ถ้าเราใช้ป้ายกำกับขนาดใหญ่และอะไรคืออันตรายของการคิดค้นฟังก์ชั่นการเติมล้ออัตโนมัติ? มีวิธีที่สามซึ่งดีกว่าอย่างใดอย่างหนึ่ง? เหตุผลของเธออาจเป็นเพราะต้องการหลีกเลี่ยงเงินเฟ้อของค่า ID ใบหน้า? ฉันสนใจที่จะฟังเกี่ยวกับเหตุผลในทางปฏิบัติด้วยเช่นกันบางทีรหัสประจำตัวขนาดใหญ่อาจใช้งานได้ในทางทฤษฎี แต่ก็ปวดหัวในทางปฏิบัติ

แอปพลิเคชันไม่คาดว่าจะจัดการกับข้อมูลจำนวนมาก ฉันสงสัยว่ามันจะถึง 10,000 บันทึกจริงภายในไม่กี่ปีถัดไป

หากมันสร้างความแตกต่างเรากำลังใช้เซิร์ฟเวอร์ Microsoft SQL แอปพลิเคชั่นเขียนด้วยภาษา C # และใช้ Linq เป็น SQL

ปรับปรุง

ขอบคุณฉันพบคำตอบและความคิดเห็นที่มีอยู่น่าสนใจ แต่ฉันเกรงว่าคุณจะเข้าใจผิดคำถามของฉันดังนั้นพวกเขาจึงมีสิ่งที่ฉันอยากรู้

ฉันไม่ได้กังวลเกี่ยวกับเหตุผลที่แท้จริงของ ID สูง หากเราไม่สามารถหาได้ด้วยตัวเองฉันสามารถถามคำถามอื่นได้ สิ่งที่ฉันสนใจคือเข้าใจกระบวนการตัดสินใจในกรณีนี้ สำหรับเรื่องนี้โปรดสมมติว่าแอปพลิเคชันจะเขียนบันทึก 1,000 รายการต่อวันจากนั้นลบ 9999รายการ ฉันเกือบจะแน่ใจว่านี่ไม่ใช่กรณี แต่นี่คือสิ่งที่หัวหน้าของฉันเชื่อเมื่อเธอขอเธอ ดังนั้นภายใต้สถานการณ์สมมุติเหล่านี้ข้อดีและข้อเสียของการใช้ bigint หรือการเขียนรหัสของเราเองซึ่งจะกำหนดรหัส (ในทางที่นำรหัสของระเบียนที่ลบไปแล้วกลับมาใช้ใหม่เพื่อให้แน่ใจว่าไม่มีช่องว่าง)

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


ดูโพสต์ของ SM Ahasan Habib ได้ที่ codeproject.com/Tips/668042/…
RLF

คุณช่วยอธิบายได้ไหม ทำ ID ใหม่เพียงรับค่า> 10,000? หรือว่า ID ใหม่มีช่องว่าง 10,000? และคาดว่าจะมี ID จำนวนเท่าใดในชีวิตของแอปในอนาคต
user2338816

1
เกี่ยวกับการค้นหา ID ที่ไม่ได้ใช้ครั้งแรกมีบทเกี่ยวกับที่แน่นอนว่าในหนังสือของ Bill Karwin "SQL Antipatterns" ดังนั้นใช่มันสามารถถูกมองว่าเป็นปฏิปักษ์!
Thomas Padron-McCarthy

คำตอบ:


24

หากไม่เห็นรหัสเป็นเรื่องยากที่จะพูดสรุปสิ่งที่เกิดขึ้น แม้ว่าส่วนใหญ่แล้วIDENTITYค่าจะถูกแคชทำให้เกิดช่องว่างในค่าหลังจากเริ่มต้นเซิร์ฟเวอร์ SQL ใหม่ ดู/programming/17587094/identity-column-value-suddenly-jumps-to-1001-in-sql-serverสำหรับคำตอบที่ดีและข้อมูลเกี่ยวกับสิ่งนั้น

INTเขตข้อมูลอย่างง่ายสามารถเก็บค่าสูงสุด 2,147,483,647 คุณสามารถเริ่มต้นค่าเอกลักษณ์ได้ที่ -2,147,483,648 โดยให้ค่า 32 บิตเต็มรูปแบบ ค่าที่แตกต่างกัน 4 พันล้าน ฉันสงสัยมากว่าคุณกำลังจะหมดคุณค่าที่จะใช้ สมมติว่าใบสมัครของคุณจะเสียค่า 1,000 สำหรับแถวที่เกิดขึ้นจริงในแต่ละเพิ่มคุณจะต้องมีการสร้างเกือบ 12,000 แถวต่อวันทุกวันจะหมดรหัสใน 6 เดือนสมมติว่าคุณเริ่มต้นIDENTITYค่าที่ 0 และถูกใช้ INT หากคุณใช้ BIGINT คุณจะต้องรอ 21 ล้านศตวรรษก่อนที่จะหมดคุณค่าหากคุณเขียน 12,000 แถวต่อวันโดยใช้ 1,000 "ค่า" ต่อแถว

ต้องบอกว่าถ้าคุณต้องการใช้BIGINTเป็นชนิดข้อมูลเขตข้อมูลเฉพาะตัวไม่มีอะไรผิดปกติกับสิ่งนั้น นั่นจะให้คุณสำหรับจุดประสงค์และจุดประสงค์ทั้งหมดซึ่งเป็นค่าที่ไม่ จำกัด ในการใช้งาน ความแตกต่างด้านประสิทธิภาพระหว่าง INT และ BIGINT นั้นไม่มีอยู่จริงบนฮาร์ดแวร์ 64 บิตที่ทันสมัยและเป็นที่นิยมมากกว่าในกรณีที่ใช้NEWID()เพื่อสร้าง GUID

หากคุณต้องการจัดการค่าของคุณเองสำหรับคอลัมน์ ID คุณสามารถสร้างตารางคีย์และจัดเตรียมวิธีการที่ใช้กันกระสุนได้โดยใช้วิธีใดวิธีหนึ่งที่แสดงในคำตอบสำหรับคำถามนี้: การ จัดการการเข้าถึงตารางคีย์พร้อมกันโดยไม่มี การหยุดชะงักใน SQL Server

ตัวเลือกอื่นสมมติว่าคุณใช้ SQL Server 2012+ จะต้องใช้SEQUENCEวัตถุเพื่อรับค่า ID สำหรับคอลัมน์ อย่างไรก็ตามคุณจะต้องกำหนดค่าลำดับเป็นค่าแคช ตัวอย่างเช่น:

CREATE SEQUENCE dbo.MySequence AS INT START WITH -2147483648 INCREMENT BY 1 NO CACHE;

ในการตอบสนองต่อการรับรู้เชิงลบของเจ้านายของคุณเกี่ยวกับตัวเลข "สูง" ฉันจะบอกว่ามันแตกต่างกันอย่างไร สมมติว่าคุณใช้INTข้อมูลกับIDENTITYคุณสามารถในความเป็นจริงเริ่มต้นIDENTITYที่2147483647และ "เพิ่ม" -1ค่าโดย นี้จะทำให้ความแตกต่างอย่างแน่นอนกับการใช้หน่วยความจำประสิทธิภาพการทำงานหรือพื้นที่ดิสก์ที่ใช้มาตั้งแต่จำนวน 32 บิตเป็น 4 ไบต์ไม่ว่าไม่มีถ้ามันเป็นหรือ 0 ในไบนารีคือเมื่อเก็บไว้ในเขตข้อมูล ลงนาม 32- บิต คือ2147483647000000000000000000000000000000000INT214748364701111111111111111111111111111111- ตัวเลขทั้งสองนั้นใช้พื้นที่จำนวนเท่ากันอย่างแม่นยำทั้งในหน่วยความจำและบนดิสก์และทั้งสองต้องใช้จำนวน CPU ที่เท่ากันเพื่อดำเนินการ การออกแบบรหัสแอปพลิเคชันของคุณให้ถูกต้องนั้นสำคัญกว่าการหมกมุ่นกับตัวเลขจริงที่จัดเก็บในฟิลด์สำคัญ

คุณถามถึงข้อดีข้อเสียของ (a) โดยใช้คอลัมน์ ID ที่มีความจุมากขึ้นเช่น a BIGINTหรือ (b) การกลิ้งโซลูชันของคุณเองเพื่อป้องกันช่องว่าง ID เพื่อตอบข้อกังวลเหล่านี้:

  1. BIGINTแทนที่จะINTเป็นชนิดข้อมูลสำหรับคอลัมน์ที่เป็นปัญหา การใช้ a BIGINTต้องมีจำนวนที่เก็บข้อมูลสองเท่าทั้งบนดิสก์และในหน่วยความจำสำหรับคอลัมน์นั้น หากคอลัมน์นั้นเป็นดัชนีคีย์หลักสำหรับตารางที่เกี่ยวข้องดัชนีแต่ละรายการที่ไม่ใช่คลัสเตอร์ที่ติดอยู่กับตารางจะเก็บBIGINTค่าที่สองเท่าของขนาดINTอีกครั้งทั้งในหน่วยความจำและบนดิสก์ SQL Server เก็บข้อมูลบนดิสก์ในหน้า 8KB ซึ่งจำนวน "แถว" ต่อ "หน้า" ขึ้นอยู่กับ "ความกว้าง" ของแต่ละแถว ตัวอย่างเช่นถ้าคุณมีตารางที่มี 10 คอลัมน์แต่ละอันและINTคุณจะสามารถจัดเก็บได้ประมาณ 160 แถวต่อหน้า หากคอลัมน์เหล่านั้นอยู่ที่ไหนแทนBIGINTคอลัมน์คุณสามารถจัดเก็บได้ 80 แถวต่อหน้าเท่านั้น สำหรับตารางที่มีจำนวนแถวมากนี่หมายความว่า I / O จำเป็นต้องอ่านและเขียนตารางจะเป็นสองเท่าในตัวอย่างนี้สำหรับจำนวนแถวที่กำหนด ที่ได้รับนี้เป็นตัวอย่างมากสวย - ถ้าคุณมีแถวประกอบด้วยเดียวINTหรือBIGINTคอลัมน์เดียวNCHAR(4000)คอลัมน์คุณต้องการจะ (simplistically) ได้รับแถวเดียวต่อหนึ่งหน้าไม่ว่าคุณจะใช้หรือINT BIGINTในสถานการณ์นี้มันจะไม่สร้างความแตกต่างที่เห็นคุณค่ามากนัก

  2. การนำเสนอสถานการณ์ของคุณเองเพื่อป้องกันช่องว่างในคอลัมน์ ID คุณต้องเขียนโค้ดของคุณในลักษณะที่กำหนดค่ารหัส "ถัดไป" ที่จะใช้ไม่ขัดแย้งกับการกระทำอื่น ๆ ที่เกิดขึ้นในตาราง บางสิ่งตามสายของความSELECT TOP(1) [ID] FROM [schema].[table]ไร้เดียงสามาถึงใจ เกิดอะไรขึ้นถ้ามีนักแสดงหลายคนพยายามที่จะเขียนแถวใหม่ไปยังตารางพร้อมกัน? นักแสดงสองคนสามารถรับค่าเดียวกันได้อย่างง่ายดายส่งผลให้เกิดข้อขัดแย้งในการเขียน การแก้ไขปัญหานี้จำเป็นต้องมีการเข้าใช้ตารางแบบอนุกรมเพื่อลดประสิทธิภาพ มีบทความมากมายที่เขียนเกี่ยวกับปัญหานี้ ฉันจะปล่อยให้ผู้อ่านทำการค้นหาในหัวข้อนั้น

บทสรุปคือ: คุณต้องเข้าใจความต้องการของคุณและประเมินทั้งจำนวนแถวและความกว้างของแถวอย่างถูกต้องพร้อมกับข้อกำหนดการทำงานพร้อมกันของใบสมัครของคุณ ตามปกติมันขึ้นอยู่กับ™


4
+1 แต่ฉันจะไม่ละทิ้งข้อกำหนดด้านพื้นที่ของ BIGINT ไม่มากสำหรับพื้นที่บนดิสก์ แต่ค่อนข้าง I / O และพื้นที่ที่สูญเสียไปในหน่วยความจำ คุณสามารถชดเชยสิ่งนี้ได้มากโดยใช้การบีบอัดข้อมูลดังนั้นคุณจึงไม่รู้สึกถึงความหนักหนาของประเภท BIGINT จนกว่าคุณจะเกิน 2 พันล้าน พวกเขาจะแก้ไขปัญหา (ฉันลังเลที่จะเรียกว่าเป็นข้อผิดพลาดต่อ se) - ในขณะที่คนไม่ควรสนใจช่องว่างและในขณะที่ผู้คนไม่ควรรีสตาร์ทเซิร์ฟเวอร์ของพวกเขา 15 ครั้งต่อวันเรามีทั้งสองสถานการณ์ ค่อนข้างแพร่หลายและมักจะตีคู่
Aaron Bertrand

3
คะแนนที่ถูกต้องมากแอรอนตามปกติ ฉันมีแนวโน้มที่จะใช้ INT ต่อไปเนื่องจาก BIGINT มีค่าใช้จ่ายมากเกินไปถ้าพวกเขาคาดหวังว่าจะมีแถวจำนวนมาก
Max Vernon

ประเภทข้อมูล BIGINT สำหรับคอลัมน์ ID จะไม่ส่งผลกระทบต่อหน่วยความจำมากนักเว้นแต่คุณจะมีหน่วยความจำหลายแสนหรือมากกว่าในเวลาเดียวกัน ถึงอย่างนั้นมันก็มีแนวโน้มที่จะเป็นเพียงส่วนเล็ก ๆ ของขนาดแถวทั้งหมด
user2338816

2
@ user2338816 นั่นคือประเด็น - ถ้าตารางใหญ่ขึ้นจะมีหน่วยความจำมากมาย และเนื่องจากคอลัมน์ข้อมูลประจำตัวมักเป็นคีย์การทำคลัสเตอร์นั่นคือ 4 ไบต์พิเศษสำหรับทุกแถวในดัชนี มันจะมีความสำคัญในทุกกรณีหรือไม่ เลขที่มันควรจะถูกละเว้น? ไม่ได้อย่างแน่นอน. ดูเหมือนว่าไม่มีใครให้ความยืดหยุ่นได้จนกว่าจะสายเกินไป
Aaron Bertrand

3
แม้ว่าคุณจะมีความคาดหวังที่ถูกต้องตามกฎหมายที่คุณอาจต้องการbigintคุณอาจจะขอบคุณตัวเองในการตัดสินใจล่วงหน้าแทนที่จะต้องการเพิ่มสิ่งนี้ลงในตารางที่มีพันล้านแถว
Martin Smith

6

ภารกิจหลักที่ต้องทำคือค้นหาสาเหตุที่ทำให้ค่าปัจจุบันสูง

คำอธิบายที่เหมาะสมที่สุดสำหรับ SQL Server เวอร์ชันก่อนหน้า SQL2012 - ถ้าคุณกำลังพูดถึงฐานข้อมูลทดสอบ - อาจเป็นได้ว่ามีการทดสอบโหลดตามด้วยการล้างข้อมูล

เริ่มต้นด้วย SQL2012 เหตุผลที่น่าจะเป็นไปได้มากที่สุดคือการเริ่มต้นใหม่หลายครั้งของ SQL Engine (ดังอธิบายในลิงค์แรกที่มีให้)

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

เป็น "ตลก" ที่ MS ระบุว่าตัวเลือกทั้งสอง (ไม่ว่าจะเป็นค่าสถานะการสืบค้นกลับ 272 หรือวัตถุลำดับใหม่) อาจส่งผลกระทบต่อประสิทธิภาพการทำงาน

มันอาจเป็นทางออกที่ดีที่สุดในการใช้ BIGINT แทนที่จะเป็น INT เพื่อให้อยู่ในด้านที่ปลอดภัยเพื่อให้ครอบคลุมการปรับปรุงต่อไปของ MS ...


ฉันอาจถามคำถามของฉันในทางที่ผิด แต่ฉันไม่สนใจที่จะหาสาเหตุ มีความน่าจะเป็นสูงที่อาจเป็นสิ่งที่จะไม่ปรากฏอีกครั้ง (ผลลัพธ์ของการทดสอบการทำงาน) หรือการตัดสินใจออกแบบที่ไม่ดีในแอปพลิเคชันซึ่งสามารถแก้ไขได้นอกฐานข้อมูล ประเด็นคือเพื่อทำความเข้าใจว่าทำไม DBA ที่มีประสบการณ์จะพิจารณาว่ามี ID สูงหรือไม่ดีกว่าการจัดการ ID ของเราเอง
rumtscho

2

Rumtscho หากคุณสร้างเพียง 1,000 แถวต่อวันมีเพียงเล็กน้อยที่จะต้องตัดสินใจ - ใช้ประเภทข้อมูล INT พร้อมฟิลด์ Identity และใช้งานได้ คณิตศาสตร์อย่างง่ายบอกว่าถ้าคุณให้วงจรชีวิตของแอป 30 ปี (ไม่น่าเป็นไปได้) คุณอาจมี 200,000 แถวต่อวันและยังอยู่ในช่วงจำนวนบวกของประเภทข้อมูล INT

การใช้ BigInt เกินความจริงในกรณีของคุณมันอาจทำให้เกิดปัญหาได้หากแอปหรือข้อมูลของคุณสามารถเข้าถึงได้ผ่าน ODBC (เช่นนำเข้าสู่ Excel หรือ MS Access ฯลฯ ) Bigint ไม่สามารถแปลได้ดีกว่าไดรเวอร์ ODBC ส่วนใหญ่ไปยังแอปเดสก์ท็อป

สำหรับ GUIDS นอกเหนือจากพื้นที่ดิสก์เพิ่มเติมและ I / O พิเศษแล้วยังมีปัญหาใหญ่ที่พวกเขาออกแบบโดยไม่ต่อเนื่องดังนั้นหากพวกเขาเป็นส่วนหนึ่งของดัชนีเรียงคุณสามารถเดาได้ว่าทุกเม็ดมีด ต้องการดัชนีที่จะใช้ --Jim


จุดดีเกี่ยวกับ GUID เว้นแต่คุณจะใช้ NEWSEQUENTIALID () - ฉันยังเห็นด้วยไม่มีเหตุผลที่ดีที่จะใช้สิ่งเหล่านี้ในคำถามนี้
Max Vernon

1

มีช่องว่างระหว่างค่าที่ใช้หรือไม่ หรือค่าเริ่มต้นคือ 10.000 และจากนั้นก็เพิ่ม 1 ทั้งหมด? บางครั้งหากจำนวนลูกค้าจะได้รับจำนวนเริ่มต้นมากกว่าศูนย์สมมติว่า 1,500 เช่นดังนั้นลูกค้าไม่ได้ตระหนักถึงระบบที่เป็น "ใหม่"

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

และอย่างที่กล่าวไว้ในการตอบสนองอื่น ๆ หากคุณกังวลเกี่ยวกับดัชนีที่หมดลงคุณไม่ควรกังวลขนาดเล็กสามารถจัดการได้เว้นแต่คุณจะมีธุรกิจเศรษฐี การประดิษฐ์กลไกในการ "กู้คืนรหัส" มีราคาแพงและเพิ่มจุดล้มเหลวและความซับซ้อนของซอฟต์แวร์

ความนับถือ


2
OP กำลังเห็นช่องว่างเมื่อเริ่มบริการใหม่ นี่เป็นเพราะปัญหานี้ นอกจากนี้ฉันไม่คิดว่า smallint เป็นการแลกเปลี่ยนที่ดีในระยะสั้นสำหรับงานที่จะแก้ไขในภายหลัง
Aaron Bertrand

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

@rumtscho จริง ๆ แล้วคำตอบนี้เน้นจุดที่ดีแม้ว่าจะไม่ได้ตอบคำถามของคุณโดยตรง: "การประดิษฐ์กลไกในการ 'กู้คืนรหัส' มีราคาแพงและเพิ่มจุดล้มเหลวและความซับซ้อนของซอฟต์แวร์"
Doktor J

@DoktorJ ฉันเห็นด้วยกับคุณ ฉันเป็นคนที่ตอบโต้คำตอบ :) แค่ต้องการที่จะกำจัดความเข้าใจผิดนั่นเป็นสาเหตุที่ฉันทิ้งความคิดเห็นแรกไว้
rumtscho

1

ถ้าฉันเป็นเจ้านายของคุณฉันจะสนใจเหตุผลที่ค่า ID สูงโดยไม่คาดคิด ... วิธีที่ฉันเห็นในแต่ละสถานการณ์ที่คุณสรุปไว้:

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

  2. หากบันทึกส่วนใหญ่ที่เขียนในตารางจะถูกลบในไม่ช้าหลังจากฉันอยากจะพิจารณาใช้สองตารางแทน ตารางชั่วคราวที่บันทึกไม่ได้ถูกเก็บไว้ในระยะยาวและอื่น ๆ ที่มีเพียงบันทึกที่เราจะสร้างไว้อย่างถาวร อีกครั้งความคาดหวังของคุณสำหรับจำนวนระเบียนระยะยาวแนะนำให้ฉันใช้ประเภทที่มีขนาดเล็กลงสำหรับคอลัมน์หลักของคุณและบันทึกไม่กี่วันต่อวันจะทำให้คุณมีปัญหาเรื่องประสิทธิภาพในการ 'ย้าย' ระเบียนจากตารางหนึ่งไปยังอีก หนึ่ง. ฉันสงสัยว่ามันไม่ใช่สถานการณ์ของคุณ แต่ลองจินตนาการว่าเว็บไซต์ช็อปปิ้งอาจต้องการเก็บตระกร้า / BasketItem และเมื่อมีการสั่งซื้อจริงข้อมูลจะถูกย้ายไปยังชุดการสั่งซื้อ / การสั่งซื้อสินค้า

เพื่อสรุป ในความคิดของฉัน BIGINT ไม่จำเป็นต้องกลัว แต่มีขนาดใหญ่โดยไม่จำเป็นสำหรับหลาย ๆ สถานการณ์ หากตารางไม่ใหญ่ขึ้นคุณจะไม่มีทางรู้ว่ามีการเลือกประเภทมากเกินไป ... แต่เมื่อคุณมีตารางที่มีหลายล้านแถวและคอลัมน์ FK จำนวนมากที่มีขนาดใหญ่เมื่อพวกมันเล็กลง - คุณอาจต้องการ ประเภทต่างๆได้รับการเลือกอย่างระมัดระวังมากขึ้น (พิจารณาไม่เฉพาะคอลัมน์หลักเท่านั้น แต่คอลัมน์หลักสำคัญทั้งหมดและการสำรองข้อมูลทั้งหมดที่คุณเก็บไว้และอื่น ๆ !) พื้นที่ดิสก์ไม่ถูกเสมอ (ให้พิจารณาดิสก์ SAN ในสถานที่ที่มีการจัดการ - เช่นเช่าพื้นที่ดิสก์)

ในสาระสำคัญฉันกำลังเถียงสำหรับการพิจารณาอย่างรอบคอบของการเลือกประเภทของข้อมูลของคุณมักจะมากกว่าบางครั้ง คุณจะไม่ทำนายรูปแบบการใช้งานให้ถูกต้องเสมอไป แต่ฉันคิดว่าคุณจะตัดสินใจได้ดีกว่าตามกฎแล้วสมมติว่า 'ใหญ่กว่าดีกว่า' เสมอ โดยทั่วไปฉันเลือกประเภทที่เล็กที่สุดที่สามารถมีช่วงค่าที่ต้องการและสมเหตุสมผลและฉันจะพิจารณา INT, SMALLINT และ TINYINT อย่างมีความสุขถ้าฉันคิดว่าค่านี้น่าจะเหมาะกับประเภทนั้นในอนาคตอันใกล้ ประเภทที่เล็กกว่านั้นไม่น่าจะใช้กับคอลัมน์ IDENTITY แต่อาจใช้กับตารางการค้นหาที่มีการตั้งค่าคีย์ด้วยตนเองอย่างมีความสุข

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


1

อะไรคือข้อดีและข้อเสียของการใช้ bigint หรือการเขียนรหัสของเราเองซึ่งจะกำหนดรหัส (ในทางที่นำรหัสของระเบียนที่ถูกลบไปแล้วกลับมาใช้ใหม่เพื่อให้แน่ใจว่าไม่มีช่องว่าง)

ใช้bigintเป็นตัวตนและอยู่กับช่องว่าง:

  • มันคือฟังก์ชั่นทั้งหมดที่สร้างขึ้น
  • คุณสามารถมั่นใจได้ว่ามันจะออกมานอกกรอบ
  • มันจะเสียพื้นที่เนื่องจากintจะให้ข้อมูลประมาณ 2M วัน หน้าเพิ่มเติมจะต้องอ่าน & เขียน; ดัชนีอาจลึก (ในหนังสือเล่มนี้สิ่งเหล่านี้ไม่ได้เป็นปัญหาที่สำคัญ)
  • คอลัมน์คีย์ตัวแทนจะต้องไม่มีความหมายดังนั้นช่องว่างก็โอเค หากการแสดงต่อผู้ใช้และช่องว่างถูกตีความว่ามีความสำคัญแสดงว่าคุณทำผิด

ม้วนของคุณเอง:

  • ทีมพัฒนาของคุณจะทำการพัฒนาและแก้ไขข้อผิดพลาดตลอดไป
  • คุณต้องการเติมช่องว่างที่หางหรือตรงกลางด้วยหรือไม่ ตัดสินใจออกแบบเพื่อโต้แย้ง
  • ทุกเขียนจะต้องล็อคปัญหาที่แข็งแกร่งในการป้องกันไม่ให้กระบวนการพร้อมกันซื้อใหม่ ID เดียวกันหรือความขัดแย้งแก้ไขโพสต์จริง
  • กรณีที่เลวร้ายที่สุดคุณจะต้องอัปเดตทุกแถวในตารางเพื่อปิดช่องว่างถ้า rowid = 1 ถูกลบ สิ่งนี้จะตอกย้ำความพร้อมกันและประสิทธิภาพการทำงานสิ่งที่มีการปรับปรุงคีย์ต่างประเทศแบบเรียงซ้อนเป็นต้น
  • ขี้เกียจหรือกระตือรือร้นเติมช่องว่าง? เกิดอะไรขึ้นกับการเกิดพร้อมกันในขณะที่สิ่งนี้กำลังเกิดขึ้น?
  • คุณจะต้องอ่านรหัสใหม่ก่อนที่จะเขียน = โหลดเพิ่มเติมใด ๆ
  • ดัชนีจะถูกต้องการในคอลัมน์ id สำหรับการค้นหาช่องว่างที่มีประสิทธิภาพ

0

หากคุณกังวลว่าจะกระทบค่าขีด จำกัด บนของ INT สำหรับ PK ของคุณให้ลองใช้ GUID ใช่ฉันรู้ว่ามัน 16 ไบต์เทียบกับ 4 ไบต์ แต่ดิสก์ราคาถูก

นี่เป็นสิ่งที่ดีเขียนขึ้นของข้อดีและข้อเสีย


4
+1 เพราะนี่เป็นวิธีแก้ปัญหา แต่ดูความคิดเห็นของ Aaron ในคำตอบของ Maxสำหรับเหตุผลที่ว่า "ดิสก์ราคาถูก" ไม่ใช่เหตุผลที่จะใช้ GUID โดยไม่ต้องชั่งน้ำหนักตัวเลือกอย่างระมัดระวัง
แจ็คดักลาส

1
นี่คือบทความที่ดีกว่าจากดัชนี SQL Server และผู้เชี่ยวชาญด้านสถาปัตยกรรมมากกว่านักพัฒนา: sqlskills.com/blogs/kimberly/disk-space-is-cheap
Aaron Bertrand

โอ้และแน่นอนระวังการแยกหน้าจาก NEWID ()
Max Vernon

1
เจ้านายของฉันดูเหมือนจะคัดค้านค่าที่สูงเพียงอย่างเดียวเพราะพวกเขาดูสูง ฉันหวังว่าคำถามนี้จะแสดงให้ฉันเห็นถึงการคัดค้านที่เป็นไปได้มากขึ้น แต่ถ้านี่เป็นหนึ่งในข้อโต้แย้งหลักของเธอเธออาจตอบโต้ต่อ GUID ได้มากกว่าเดิม
rumtscho

1
@rumtscho บอกหัวหน้าของคุณว่าหมายเลขตัวแทนเป็นเพียงตัวเลขที่ไม่มีความหมาย ("ขนาด" ของจำนวนนั้นไม่เกี่ยวข้อง) และช่องว่างในลำดับนั้นเป็นธรรมชาติและหลีกเลี่ยงไม่ได้
Aaron Bertrand

0

คีย์หลัก RDBMS (คอลัมน์มักจะมีชื่อว่า 'ID')
ไม่สามารถหลีกเลี่ยงช่องว่างในคอลัมน์ (ฟิลด์) การรวมอัตโนมัติ RDBMS พวกเขามีวัตถุประสงค์หลักเพื่อสร้าง PKs ที่ไม่ซ้ำกัน สำหรับประสิทธิภาพการทำงานผลิตภัณฑ์หลักจะจัดสรรสิ่งเหล่านี้เป็นแบทช์ดังนั้นกลไกการกู้คืนอัตโนมัติสำหรับข้อบกพร่องในการทำงานตามปกติต่างๆอาจส่งผลให้ไม่มีการใช้งานตัวเลข นี่เป็นปกติ.

ลำดับที่ไม่แตก
เมื่อคุณต้องการหมายเลขลำดับที่ไม่แตกเช่นผู้ใช้คาดหวังบ่อยครั้งควรเป็นคอลัมน์แยกต่างหากที่กำหนดโดยทางโปรแกรมและไม่ควรเป็น PK ดังนั้น 1,000 ระเบียนทั้งหมดสามารถมีหมายเลขเดียวกันในคอลัมน์นั้น

เหตุใดผู้ใช้จึงต้องการลำดับที่ไม่เสียหาย
หมายเลขลำดับที่หายไปเป็นสัญญาณขั้นพื้นฐานที่สุดของข้อผิดพลาดที่ไม่เปิดเผยในการตรวจสอบทุกประเภท หลักการ "การทำบัญชี -101" นี้เป็นที่แพร่หลาย อย่างไรก็ตามสิ่งที่ใช้งานได้กับบันทึกจำนวนเล็กน้อยที่ดูแลด้วยมือมีปัญหาร้ายแรงเมื่อนำไปใช้กับระเบียนจำนวนมากในฐานข้อมูล ...

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.