ควรใช้ TINYINT บน INT เมื่อใด


91

โดยทั่วไปฉันมักจะใช้ Ints ฉันรู้ว่าในทางทฤษฎีแล้วนี่ไม่ใช่วิธีปฏิบัติที่ดีที่สุดเนื่องจากคุณควรใช้ประเภทข้อมูลที่เล็กที่สุดที่จะรับประกันการจัดเก็บข้อมูล

ตัวอย่างเช่นจะดีกว่าที่จะใช้tinyintเมื่อคุณรู้ว่าข้อมูลเดียวที่คุณจะจัดเก็บคือ 1, 0 หรือ null (มีโอกาสน้อยมากที่จะขยายไปยัง 2 หรือ 3 ในภายหลัง)

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

อะไรคือผลกระทบของการใช้tinyint(หรือsmallintหรือbigintมากกว่า) intนอกเหนือจากการประหยัดพื้นที่บนฮาร์ดไดรฟ์ของคุณ?


2
นี่เป็นคำถามที่ดีมาก (+1) MySQL มี SELECT ... ANALYZE ANALYZE () ซึ่งได้แนะนำให้เลือกชนิดข้อมูลที่เล็กที่สุดที่ตารางควรมีสำหรับ SELECT ที่กำหนด นั่นเป็นแรงบันดาลใจส่วนหนึ่งที่อยู่เบื้องหลังคำตอบของฉัน
RolandoMySQLDBA

3
คำถามที่ดี แต่เพื่อให้แม่นยำช่วงจิ๋วของสีคือ 0-255 บิตฟิลด์คือ 0 หรือ 1 (หรือ NULL) ค่าใช้จ่ายในการจัดเก็บสำหรับ tinyint คือ 1 ไบต์ ทุกๆ 8 บิตในตารางจะมีราคา 1 ไบต์ของที่เก็บข้อมูล msdn.microsoft.com/en-us/library/ms187745.aspxและmsdn.microsoft.com/en-us/library/ms177603.aspx
billinkc

@billinkc ถูกต้อง นั่นคือเหตุผลที่ฉันพูดถึงความเป็นไปได้ในการขยายคอลัมน์เพื่อรวมค่า 2 หรือ 3 หากคุณรวม 2 หรือ 3 คุณต้องใช้ Tinyint (ขนาดเล็กที่สุด)
ริชาร์ด

1
"ตัวอย่างเช่นจะเป็นการดีกว่าถ้าใช้ขนาดเล็กเมื่อคุณรู้ว่าข้อมูลเดียวที่คุณจะจัดเก็บคือ 1, 0 หรือ null (มีโอกาสน้อยมากที่จะขยายไปยัง 2 หรือ 3 ในภายหลัง)" ฉันจะใช้ ENUM สำหรับสิ่งนั้น สิ่งเหล่านี้ถูกเก็บไว้เป็นบิตฟิลด์และอื่น ๆ อีกมากมายได้ชี้ให้เห็นที่นี่การออมเล็ก ๆ น้อย ๆ ต่อการบันทึกรวมถึงการออมขนาดใหญ่บนฐานข้อมูลทั้งหมด - แม้แต่ moreso ถ้าคอลัมน์ถูกทำดัชนี

2
@ user6665 I'd use an ENUM for such a thing.ไม่ได้อยู่ใน SQL Server คุณจะไม่ทำเช่นนั้นเนื่องจากมันไม่มีการแจกแจงใด ๆ
underscore_d

คำตอบ:


92

พื้นที่ดิสก์มีราคาถูก ... นั่นไม่ใช่ประเด็น!

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

ข้อความที่สำคัญคือเรื่องการออกแบบ ความแตกต่างจะไม่ปรากฏในฐานข้อมูลส่วนบุคคลบนเซิร์ฟเวอร์ spec'd อย่างเหมาะสมจนกว่าคุณจะไปถึงอาณาเขต VLDB แต่ถ้าคุณสามารถบันทึกสองสามไบต์ทำไมไม่ทำเช่นนั้น

ฉันนึกถึงสภาพแวดล้อมที่อธิบายไว้ในคำถามก่อนหน้านี้ ฐานข้อมูล 400+ ขนาดตั้งแต่ 50mb-50GB ต่ออินสแตนซ์ของ SQL การขัดสองสามไบต์ต่อเร็กคอร์ดต่อตารางต่อฐานข้อมูลทั่วทั้งสภาพแวดล้อมนั้นสามารถสร้างความแตกต่างที่สำคัญได้


29

นอกจากคำตอบอื่น ๆ ...

แถวและรายการดัชนีจะถูกเก็บไว้ในหน้า 8k ดังนั้นหนึ่งล้านแถวที่ 3 ไบต์ต่อแถวไม่ใช่ 3 MB บนดิสก์: มันมีผลต่อจำนวนแถวต่อหน้า ("ความหนาแน่นของหน้า")

เช่นเดียวกับ nvarchar ถึง varchar, smalldatetime กับ datetime, int to tinyint ฯลฯ

แก้ไขมิถุนายน 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

บทความนี้ระบุ

เกณฑ์สำคัญคือความสำคัญเชิงสถิติและอัตราส่วนหน้าต่อแถว

ดังนั้นการเลือกประเภทข้อมูลจึงมีความสำคัญ


5
จุดดี. ตัวอย่างกรณีที่เลวร้ายที่สุดที่แน่นอนคือแถว 4028 ไบต์ประกอบด้วยคอลัมน์ความยาวคงที่ทั้งหมดที่คุณต้องการเพิ่มคอลัมน์ การเพิ่มอักษรขนาดเล็กจะนำคุณไปสู่ ​​4030 (2 แถวต่อหน้า) แต่ int จะผลักคุณข้ามขอบเขต (1 แถวต่อหน้า 4028 ไบต์เสียต่อหน้า)
Mark Storey-Smith

ฉันเคยทำการทดสอบประสิทธิภาพใน int กับ bigint บันทึก 1 ล้านบันทึกเปรียบเทียบเวลาและจัดเก็บและเรียกคืนข้อมูลทีละรายการและวัดประสิทธิภาพอีกครั้ง ฉันไม่เห็นความแตกต่างที่สำคัญ ฉันจะทำแบบทดสอบประสิทธิภาพเดียวกันสำหรับ int vs tinyint ฉันคิดว่ามันสามารถถูกละเลยได้ถึง 80% ของแอปพลิเคชันส่งผลให้มีประเภทข้อมูลที่สอดคล้องกันมากขึ้นและมีค่าใช้จ่ายในการบำรุงรักษาน้อยลง
Saeed Neamati

1
@SeedNeamati คุณอาจต้องการอ่านบทความใหม่อีกครั้งจากคำตอบของ Mark (" คุณเคยได้ยินหรือไม่ ... เรามาทำสิ่งนี้ให้สำเร็จ - เราจะกังวลเกี่ยวกับการแสดงในภายหลังหรือไม่ ... ฉันได้ยินเรื่องนี้ตลอดเวลา ... ") และgbn ของที่นี่ . ฉันคิดว่าการนำกลับบ้านคือการที่ทางเลือกที่ไร้ประสิทธิภาพจะแสดงแถบของมันในระดับที่เหมาะสมและความกล้าของ OP ไม่ผิด
ruffin

14

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

ฉันคาดหวังว่าจะพบว่าการตรวจสอบรายการดัชนีในหน้า BTREE จะเร็วขึ้นเล็กน้อยเมื่อใช้กับชนิดข้อมูลที่เล็กลง อย่างไรก็ตาม VARCHAR ใด ๆ ที่เกี่ยวข้องในรายการดัชนีจะชดเชย (ลบล้าง) ประสิทธิภาพที่เพิ่มขึ้นจากการใช้ TINYINT ผ่าน INT

อย่างไรก็ตามหากรายการดัชนีมีรายการประกอบและทั้งหมดเป็นจำนวนเต็มจำนวนเต็มที่น้อยกว่าก็จะดีกว่าและเร็วกว่า


13

ทุกสิ่งกลายเป็นความซับซ้อนเมื่อฐานข้อมูลใหญ่ขึ้น:

  • หน้าต่างการบำรุงรักษาจำเป็นต้องขยายหรือกำหนดเวลาใหม่
  • การสำรองข้อมูล (การสำรองข้อมูลเต็มรูปแบบในตอนท้ายของวันกลายเป็นเรื่องกินเวลาที่ไร้สาระดังนั้นคุณต้องมีส่วนต่างหรือแม้แต่บันทึกข้อมูลสำรองและทำแบบเต็มสัปดาห์ละครั้งอาจจะเดือนละครั้ง)
  • การบำรุงรักษาของการแสดงกลายเป็นตัวกินเวลา (การสร้างดัชนีบนตารางหลายล้านแถวนั้นใช้เวลาเล็กน้อยในการดำเนินการ) และจำเป็นต้องได้รับการจัดตารางใหม่และแย่ลงถ้าตารางกว้าง ...
  • และการส่งข้อมูลสำรอง 100Gb ผ่านเครือข่ายไม่ใช่สิ่งที่ฉันเรียกว่าเค้ก - โดยเฉพาะถ้าเครือข่าย (ด้วยเหตุผลบางอย่างที่ไม่ทราบสาเหตุ) จะดื้อรั้นในการทิ้งการเชื่อมต่อบนเครื่องหมาย 75Gb ... (เกิดขึ้นกับการติดตั้ง กำลังสำรองข้อมูลไปยังไดรฟ์ที่แมปบนเครือข่าย - เครือข่าย) ...

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

หากคุณรู้ว่ามีบางคอลัมน์ในตารางที่จะมีหลายล้านแถวหรือแม้กระทั่งตารางเล็ก ๆ ที่จะ FK'ed เป็นหลายล้านแถวที่ไม่ต้องการจำนวนเต็ม 4 ไบต์ในการจัดเก็บข้อมูล แต่ 2 ไบต์จะ พอเพียง - ใช้SMALLINT ถ้าค่าในช่วง 0-255 ก็พอTINYINT ธงใช่ / ไม่ใช่หรือ มีBIT


9

ในขณะที่สำหรับtinyintVS intมีความแตกต่างที่ชัดเจนเช่นพื้นที่ในดิสก์แยกหน้าและเวลาการบำรุงรักษาจะไม่มีใด ๆ varcharเหล่านี้สำหรับ

เหตุใดจึงไม่ประกาศเขตข้อมูลข้อความทั้งหมดvarchar(4000)เนื่องจากมันจะใช้พื้นที่เพียงอย่างเดียวต่อไปหรือไม่ ยิ่งกว่านั้นคุณจะมั่นใจได้ว่าข้อมูลของคุณจะไม่ถูกตัดทอน

คำตอบคือแน่นอน:

  1. ชี้แจงความตั้งใจของคุณ (เนื่องจากไม่มีใครเข้าใจว่าทำไมฟิลด์ชื่อควรมีอักขระถึง 4,000 ตัว)
  2. ตรวจสอบความถูกต้องตามที่คุณต้องการเพื่อให้แน่ใจว่าไม่มีใครเข้าสู่ประวัติทั้งหมดเป็นชื่อ

เหตุผลเดียวกันนี้ใช้กับtinyintเช่นกัน


3
นี่เป็นเธรดที่เก่ากว่า แต่การชี้แจงและการตรวจสอบไม่ได้เป็นเพียงเหตุผลเดียว หากคุณมี VARCHAR (4000) สำหรับบางสิ่งที่ควรเป็น VARCHAR (20) แผนแบบสอบถามจะคิดว่าความต้องการหน่วยความจำและ CPU ของคุณนั้นเป็นทวีคูณของสิ่งที่ควรจะเป็นตามคอลัมน์นั้น ฉันไม่ได้ใช้เวลาในการทำเช่นนี้ แต่ฉันเดาว่าคุณอาจจะเห็นสิ่งนี้ได้โดยดูที่แผนแบบสอบถามสำหรับ VARCHAR (20) แล้วเปลี่ยนเป็น VARCHAR (4000) และตรวจสอบต้นทุนโดยประมาณ

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