มีข้อเสียในการใช้ varchar (255) ทั่วไปสำหรับฟิลด์ที่เป็นข้อความทั้งหมดหรือไม่?


100

ฉันมีcontactsตารางที่มีสาขาต่าง ๆ เช่นpostcode, first name, last name, town, country, phone numberฯลฯ ซึ่งทั้งหมดนี้จะถูกกำหนดเป็นVARCHAR(255)แม้ว่าจะไม่มีข้อมูลเหล่านี้จะเคยมาใกล้เคียงกับที่มี 255 ตัวอักษร (หากคุณสงสัยก็เป็นเช่นนี้เพราะการย้ายข้อมูล Ruby on Rails จะจับคู่ฟิลด์ String เป็นVARCHAR(255)ค่าเริ่มต้นและฉันไม่เคยใส่ใจที่จะแทนที่มัน)

เนื่องจาก VARCHAR จะจัดเก็บเฉพาะจำนวนอักขระจริงของฟิลด์ (พร้อมกับความยาวฟิลด์) มีข้อได้เปรียบที่แตกต่าง (ประสิทธิภาพหรืออย่างอื่น) ในการใช้พูดVARCHAR(16)ทับVARCHAR(255)หรือไม่?

นอกจากนี้ฟิลด์เหล่านี้ส่วนใหญ่มีดัชนีอยู่ด้วย ขนาด VARCHAR ที่ใหญ่ขึ้นบนสนามมีผลต่อขนาดหรือประสิทธิภาพของดัชนีหรือไม่?

ฉันใช้ MySQL 5


2
@ceejayoz โดยระบุว่าคำตอบที่ยอมรับนั้นไม่ถูกต้องโดยไม่ต้องอธิบายว่าทำไมไม่ช่วยจริงๆ สิ่งที่ทำให้แย่ลงไปกว่านั้นคือคำตอบที่ยอมรับสามารถเปลี่ยนแปลงได้ตลอดเวลาและความคิดเห็นของคุณจะทำให้ผู้คนสับสนคิดว่าคำตอบที่ยอมรับใหม่นั้นไม่ถูกต้อง
Gili

1
@Gili ลบความคิดเห็นของฉันเนื่องจาก OP เปลี่ยนการยอมรับของพวกเขา จุดดีในอนาคตฉันจะระบุคำตอบที่ฉันกำลังพูดถึงและทำไม
ceejayoz

คำตอบอื่น ๆ ในคำถามที่ซ้ำกันนี้stackoverflow.com/questions/1262174/…
James McMahon

คำตอบ:


129

ในการจัดเก็บข้อมูลVARCHAR(255)นั้นฉลาดพอที่จะจัดเก็บเฉพาะความยาวที่คุณต้องการในแถวที่กำหนดCHAR(255)ซึ่งแตกต่างจากที่เก็บ 255 อักขระ

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

เมื่อแบบสอบถามของคุณสร้างตารางชั่วคราวโดยปริยายตัวอย่างเช่นในขณะที่กำลังเรียงลำดับหรือGROUP BYอาจใช้หน่วยความจำจำนวนมาก หากคุณใช้VARCHAR(255)ฟิลด์จำนวนมากสำหรับข้อมูลที่ไม่จำเป็นต้องยาวขนาดนั้นอาจทำให้ตารางชั่วคราวมีขนาดใหญ่มาก

นอกจากนี้คุณอาจต้องการทราบว่าลักษณะการทำงานของ "การเว้นระยะห่าง" หมายความว่าสตริงที่ประกาศด้วยชุดอักขระ utf8 จะมีขนาดสามไบต์ต่ออักขระแม้กระทั่งสำหรับสตริงที่คุณจัดเก็บด้วยเนื้อหาไบต์เดี่ยว (เช่น ascii หรือละติน 1 อักขระ) และในทำนองเดียวกันชุดอักขระ utf8mb4 ทำให้สตริงขยายออกเป็นสี่ไบต์ต่ออักขระในหน่วยความจำ

ดังนั้นVARCHAR(255)ใน utf8 ที่จัดเก็บสตริงสั้น ๆ เช่น "ไม่มีความเห็น" จะใช้เวลา 11 ไบต์บนดิสก์ (อักขระอักขระที่ต่ำกว่าสิบตัวบวกความยาวหนึ่งไบต์) แต่ใช้หน่วยความจำ 765 ไบต์ดังนั้นในตาราง temp หรือผลลัพธ์ที่เรียงลำดับ

ฉันได้ช่วยผู้ใช้ MySQL ที่สร้างตารางอุณหภูมิ 1.5GB บ่อยๆโดยไม่รู้ตัวและทำให้เต็มพื้นที่ดิสก์ พวกเขามีVARCHAR(255)คอลัมน์จำนวนมากซึ่งในทางปฏิบัติเก็บสตริงที่สั้นมาก

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

เป็นเรื่องยากที่จะทราบว่าที่อยู่ไปรษณีย์ที่ยาวที่สุดคืออะไรซึ่งเป็นสาเหตุที่หลายคนเลือกVARCHARที่อยู่ที่ยาวกว่าที่อยู่ใด ๆ อย่างแน่นอน และ 255 เป็นเรื่องปกติเนื่องจากเป็นความยาวสูงสุดของ a VARCHARซึ่งสามารถเข้ารหัสความยาวได้ด้วยหนึ่งไบต์ นอกจากนี้ยังเป็นVARCHARความยาวสูงสุดใน MySQL ที่เก่ากว่า 5.0


6
ฉันคิดเสมอว่า255ถูกใช้เพื่อให้ความยาวของสตริงพอดีกับไบต์เดียว
BlueRaja - Danny Pflughoeft

3
@BlueRaja: นั่นอาจเป็นจริงสำหรับฐานข้อมูลที่โครงสร้างไฟล์ภายในเข้ารหัสความยาวของสตริงในไบต์เดียวหรือหากเข้ารหัสสตริงสั้น ๆ ในไบต์เดียว แต่ไม่เป็นความจริงอีกต่อไปสำหรับฐานข้อมูลส่วนใหญ่
Bill Karwin

7
@BlueRaja: InnoDB ไม่เก็บความยาวของ varchar ต่อไปนี้ แต่จะเก็บชุดของการชดเชยฟิลด์สำหรับทุกฟิลด์ในแถว การชดเชยฟิลด์เหล่านี้อาจเป็น 1 ไบต์ถ้าขนาดแถวทั้งหมดน้อยกว่า 127 ไบต์หรือ 2 ไบต์ ดูforge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin

6
@BlueRaja: MyISAM (สำหรับผู้ที่ยังใช้งานอยู่) จะเก็บความยาวของ varchar และสามารถจัดเก็บได้ใน 1 หรือ 2 ไบต์ อย่างไรก็ตาม: "เมื่อส่งคีย์ไปยังตัวจัดการสำหรับ index_read () หรือ records_in_range เราจะใช้ความยาว 2 ไบต์สำหรับ VARCHAR เพื่อทำให้สิ่งต่างๆง่ายขึ้นเสมอ" ดูforge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin

1
คำถามเดียว - การเรียงลำดับและจัดกลุ่มตามฟิลด์ใด ๆ หรือฟิลด์ varchar เอง?
Rohit Banga

24

นอกจากนี้ให้มีขนาดและประสิทธิภาพการพิจารณาของการตั้งค่าขนาดของ varchar (และอาจจะเป็นสิ่งที่สำคัญมากขึ้นเช่นการจัดเก็บข้อมูลและการประมวลผลได้รับราคาถูกทุกวินาที) ข้อเสียของการใช้ varchar (255) ว่า "เพียงเพราะ" จะลดลงความสมบูรณ์ของข้อมูล

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

ตัวอย่างเช่นหากคุณมีฟิลด์ที่ยอมรับสตริงอักขระสองตัวสำหรับตัวย่อประเทศคุณก็ไม่มีเหตุผลที่เป็นไปได้ที่จะคาดหวังให้ผู้ใช้ของคุณ (ในบริบทนี้โปรแกรมเมอร์) ป้อนชื่อประเทศแบบเต็ม เนื่องจากคุณไม่ต้องการให้พวกเขาเข้าสู่ "Antigua and Barbuda" (AG) หรือ "Heard Island and McDonald Islands" (HM) คุณจึงไม่อนุญาตให้เข้าสู่ชั้นฐานข้อมูล นอกจากนี้ยังมีแนวโน้มว่าโปรแกรมเมอร์บางคนยังไม่ได้ RTFMed เอกสารการออกแบบ ( ซึ่งมีอยู่จริง ) เพื่อให้ทราบว่าจะไม่ทำเช่นนี้

ตั้งค่าฟิลด์ให้ยอมรับอักขระสองตัวและปล่อยให้ RDBMS จัดการกับมัน (อย่างสง่างามโดยการตัดทอนหรืออย่างไม่เหมาะสมโดยการปฏิเสธ SQL ด้วยข้อผิดพลาด)

ตัวอย่างข้อมูลจริงที่ไม่มีเหตุผลที่จะยาวเกินกำหนด:

  • รหัสไปรษณีย์ของแคนาดาอยู่ในรูปแบบ A1A1A1 และมีความยาว 6 อักขระเสมอแม้กระทั่งสำหรับซานตาคลอส (อักขระ 6 ตัวไม่รวมช่องว่างที่สามารถระบุให้ชัดเจนได้)
  • ที่อยู่อีเมลสูงสุด 64 ไบต์ก่อนหน้า @ สูงสุด 255 ไบต์หลัง ไม่อีกต่อไปเกรงว่าคุณจะทำลายอินเทอร์เน็ต
  • หมายเลขโทรศัพท์ในอเมริกาเหนือไม่เกิน 10 หลัก (ไม่รวมรหัสประเทศ)
  • คอมพิวเตอร์ที่ใช้ (เวอร์ชันล่าสุด) Windows ไม่สามารถมีชื่อคอมพิวเตอร์ที่ยาวเกิน 63 ไบต์ได้แม้ว่าจะไม่แนะนำให้ใช้มากกว่า 15 และจะทำให้เซิร์ฟเวอร์ Windows NT ของคุณเสียหาย
  • อักษรย่อของรัฐมี 2 อักขระ (เช่นรหัสประเทศที่ยกตัวอย่างด้านบน)
  • หมายเลขติดตามของ UPSมีความยาว 18-, 12-, 11- หรือ 9 อักขระ ตัวเลข 18 ตัวเริ่มต้นด้วย "1Z" และตัวเลข 11 ตัวขึ้นต้นด้วย "T" ซึ่งทำให้คุณสงสัยว่าพวกเขาส่งพัสดุเหล่านั้นทั้งหมดได้อย่างไรหากพวกเขาไม่ทราบความแตกต่างระหว่างตัวอักษรและตัวเลข

และอื่น ๆ ...

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

การใช้ varchar (n) แทน varchar (255) จะช่วยขจัดปัญหาที่ผู้ใช้ (ผู้ใช้ปลายทางโปรแกรมเมอร์โปรแกรมอื่น ๆ ) ป้อนข้อมูลที่ยาวโดยไม่คาดคิดซึ่งจะกลับมาหลอกหลอนโค้ดของคุณในภายหลัง

และฉันไม่ได้บอกว่าคุณไม่ควรใช้ข้อ จำกัด นี้ในรหัสตรรกะทางธุรกิจที่แอปพลิเคชันของคุณใช้


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

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

แอปพลิเคชั่นส่วนใหญ่จะมีการตรวจสอบข้อมูลก่อนที่จะส่งไปยังฐานข้อมูล ...
Cobby

2
แน่นอน มากที่สุด แต่ฉันรู้สึกว่าที่นี่คุณกำลังสมมติว่านักพัฒนาที่กำลังพัฒนาแอปพลิเคชันใหม่สำหรับฐานข้อมูลที่มีอยู่ตระหนักถึงข้อ จำกัด ของข้อมูล (เราไม่ใช่ผู้เชี่ยวชาญในข้อมูลทุกประเภทและวิธีการนำไปใช้ในทุกฐานข้อมูล ). เพียงเพราะคุณสามารถตรวจสอบข้อมูลในแอปพลิเคชันของคุณไม่ได้หมายความว่าคุณทำ
shufler

3
the design documentation (which surely exists)ฮะ. : D
Camilo Martin

14

ฉันอยู่กับคุณ การใส่ใจในรายละเอียดที่จุกจิกทำให้ปวดคอและมีค่า จำกัด

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

หากคุณใช้เฉพาะช่อง CHAR คุณจะได้รับแถวที่มีความยาวคงที่ สิ่งนี้สามารถบันทึกการรีเฟรชดิสก์ได้จริงหากคุณเลือกขนาดที่ถูกต้องสำหรับฟิลด์ คุณอาจได้รับข้อมูลที่อัดแน่นมากขึ้น (I / O น้อยลงสำหรับการสแกนตาราง) และการอัปเดตที่เร็วขึ้น (ง่ายต่อการค้นหาพื้นที่เปิดในบล็อกสำหรับการอัปเดตและส่วนแทรก)

อย่างไรก็ตามหากคุณประมาณขนาดของคุณมากเกินไปหรือขนาดข้อมูลจริงของคุณมีความผันแปรคุณจะต้องสิ้นเปลืองพื้นที่ด้วยช่อง CHAR ข้อมูลจะถูกรวบรวมไว้อย่างหนาแน่นน้อยลง (ทำให้มี I / O มากขึ้นสำหรับการดึงข้อมูลจำนวนมาก)

โดยทั่วไปประโยชน์ด้านประสิทธิภาพจากการพยายามใส่ขนาดในช่องตัวแปรจะมีน้อย คุณสามารถเปรียบเทียบได้อย่างง่ายดายโดยใช้ VARCHAR (255) เทียบกับ CHAR (x) เพื่อดูว่าคุณสามารถวัดความแตกต่างได้หรือไม่

อย่างไรก็ตามบางครั้งฉันต้องระบุคำใบ้ "เล็ก" "กลาง" "ใหญ่" ดังนั้นฉันจึงใช้ 16, 64 และ 255 สำหรับขนาด


13

ทุกวันนี้ฉันนึกไม่ออกเลยว่ามันมีความสำคัญมากกว่านี้จริงๆ

มีค่าใช้จ่ายในการคำนวณในการใช้ฟิลด์ความยาวตัวแปร แต่ด้วย CPU ที่มากเกินไปในปัจจุบันจึงไม่คุ้มค่าที่จะพิจารณา ระบบ I / O ทำงานช้ามากจนทำให้ต้นทุนในการคำนวณสามารถจัดการกับ varchars ได้อย่างมีประสิทธิภาพ ในความเป็นจริงราคาของ varchar ในการคำนวณน่าจะเป็นผลกำไรสุทธิจากจำนวนพื้นที่ดิสก์ที่บันทึกโดยใช้ฟิลด์ความยาวตัวแปรในฟิลด์ความยาวคงที่ คุณมักจะมีความหนาแน่นของแถวมากกว่า

ตอนนี้ความซับซ้อนของฟิลด์ varchar คือคุณไม่สามารถค้นหาเรกคอร์ดผ่านหมายเลขเร็กคอร์ดได้อย่างง่ายดาย เมื่อคุณมีขนาดแถวที่มีความยาวคงที่ (พร้อมช่องความยาวคงที่) การคำนวณบล็อกดิสก์ที่ id แถวชี้ไปนั้นเป็นเรื่องเล็กน้อย ด้วยขนาดของแถวที่มีความยาวตัวแปรชนิดนั้นจะออกไปนอกหน้าต่าง

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

แต่เนื่องจากเรามีฟิลด์ varchar ในปัจจุบันค่าเดียวของ varchar (16) ส่วน varchar (255) คือ DB จะบังคับใช้ขีด จำกัด 16 อักขระบน varchar (16) ถ้าแบบจำลอง DB ควรจะเป็นตัวแทนของโมเดลข้อมูลทางกายภาพจริงๆการมีความยาวของฟิลด์จะมีค่า อย่างไรก็ตามหากเป็นเพียง "ที่เก็บข้อมูล" แทนที่จะเป็น "แบบจำลองและที่เก็บข้อมูล" ก็ไม่จำเป็นต้องมีอะไรอีก

จากนั้นคุณเพียงแค่ต้องแยกแยะระหว่างฟิลด์ข้อความที่จัดทำดัชนีได้ (varchar ดังกล่าว) กับสิ่งที่ไม่ใช่ (เช่นฟิลด์ข้อความหรือ CLOB) ฟิลด์ที่จัดทำดัชนีได้มักจะมีข้อ จำกัด เกี่ยวกับขนาดเพื่ออำนวยความสะดวกในการจัดทำดัชนีในขณะที่ฟิลด์ CLOB ไม่มี (ภายในเหตุผล)


5

จากประสบการณ์ของฉันหากคุณอนุญาตประเภทข้อมูล 255 อักขระผู้ใช้ที่โง่เขลา (หรือผู้ทดสอบที่มีประสบการณ์บางคน) จะเติมเต็มให้

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

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


0

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

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

ค่าเริ่มต้นปกติจะเป็น 50 imho จากนั้นเพิ่มขึ้นเมื่อต้องการพิสูจน์


ขอบคุณ. ฉันเห็นด้วยอย่างแน่นอนเกี่ยวกับการปฏิบัติที่ดี มันเป็นด้านประสิทธิภาพที่ฉันอยากชี้แจงจริงๆ
Olly

0

ในบริบท mysql อาจมีความสำคัญเมื่อทำงานกับดัชนีในคอลัมน์ varchar ดังกล่าวเนื่องจาก mysql มีค่าสูงสุด ขีด จำกัด 767 ไบต์ต่อแถวดัชนี

ซึ่งหมายความว่าเมื่อเพิ่มดัชนีในคอลัมน์ varchar 255 หลายคอลัมน์คุณจะไปถึงขีด จำกัด นี้ได้ค่อนข้างเร็ว / เร็วกว่าในคอลัมน์ utf8 หรือ utf8mb4 ตามที่ระบุไว้ในคำตอบด้านบน

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