ความหมายของประสิทธิภาพของขนาด MySQL VARCHAR


45

มีความแตกต่างของประสิทธิภาพใน MySQL ระหว่างขนาด varchar หรือไม่ ยกตัวอย่างเช่นและvarchar(25) varchar(64000)ถ้าไม่มีมีเหตุผลที่จะไม่ประกาศ varchars ทั้งหมดที่มีขนาดสูงสุดเพียงเพื่อให้แน่ใจว่าคุณไม่ได้ออกจากห้อง?


3
+1 คำถามนี้ใช้กับ DBMS ทั้งหมด การสังเกตของฉันหลายขนาด varchar มีแนวโน้มที่จะเติบโต
bernd_k

5
ไม่ MySQL แต่โพสต์บล็อกนี้โดย DepeszอาจตอบคำถามของคุณสำหรับPostgreSQL
xenoterracide

คำตอบ:


29

คุณต้องตระหนักถึงข้อเสียของการใช้ CHAR กับ VARCHAR

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

ด้วยฟิลด์ VARCHAR คุณจะได้รับเรื่องราวที่แตกต่างอย่างสิ้นเชิง ตัวอย่างเช่น VARCHAR (15) จะจัดสรรข้อมูลแบบไดนามิกมากถึง 16 ไบต์สูงสุด 15 สำหรับข้อมูลและอย่างน้อย 1 ไบต์เพิ่มเติมเพื่อจัดเก็บความยาวของข้อมูล หากคุณมีสตริง 'hello' ในการจัดเก็บที่ใช้เวลา 6 ไบต์ไม่ใช่ 5 การจัดการสตริงต้องดำเนินการตรวจสอบความยาวบางรูปแบบในทุกกรณี

การแลกเปลี่ยนนั้นชัดเจนมากขึ้นเมื่อคุณทำสองสิ่ง:
1. จัดเก็บล้านหรือหลายพันล้านแถว
2. การทำดัชนีคอลัมน์ที่มีทั้งแบบ CHAR หรือ VARCHAR

TRADEOFF # 1

เห็นได้ชัดว่า VARCHAR มีความได้เปรียบเนื่องจากข้อมูลที่มีความยาวผันแปรจะสร้างแถวที่เล็กกว่าและดังนั้นจึงมีขนาดเล็กลง

TRADEOFF # 2

เนื่องจากเขตข้อมูล CHAR ต้องการการจัดการสตริงน้อยกว่าเนื่องจากความกว้างของเขตข้อมูลคงที่การค้นหาดัชนีเทียบกับเขตข้อมูล CHAR จะเร็วกว่าค่าเฉลี่ย 20% ของเขตข้อมูล VARCHAR นี่ไม่ใช่การคาดเดาใด ๆ ในส่วนของฉัน หนังสือการออกแบบและปรับแต่งฐานข้อมูล MySQLทำสิ่งที่ยอดเยี่ยมในตาราง MyISAM เพื่อพิสูจน์สิ่งนี้ ตัวอย่างในหนังสือทำสิ่งต่อไปนี้:

ALTER TABLE tblname ROW_FORMAT=FIXED;

กองกำลังสั่งนี้เป็น VARCHARs ที่จะทำตัวเป็น CHARs ฉันทำสิ่งนี้ที่งานก่อนหน้าของฉันในปี 2550 และเอาตาราง 300GB และเร่งการค้นหาดัชนีขึ้น 20% โดยไม่เปลี่ยนแปลงอะไรเลย มันทำงานตามที่เผยแพร่ อย่างไรก็ตามมันสร้างตารางเกือบสองเท่าในขนาด แต่มันกลับไปที่การแลกเปลี่ยน # 1

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

SELECT * FROM tblname PROCEDURE ANALYSE();

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

หากคุณกำลังจัดเก็บที่อยู่ IP มาสก์สำหรับคอลัมน์ดังกล่าวมีความยาวสูงสุด 15 อักขระ (xxx.xxx.xxx.xxx) ฉันจะกระโดดขวาที่ CHAR (15) ใน heartbeat เนื่องจากความยาวของที่อยู่ IP จะไม่แตกต่างกันมากและความซับซ้อนที่เพิ่มขึ้นของการจัดการสตริงที่ควบคุมโดยไบต์เพิ่มเติม คุณยังสามารถทำ ANALYZE () กับคอลัมน์ดังกล่าวได้ มันอาจแนะนำ VARCHAR ด้วยซ้ำ เงินของฉันจะยังคงเป็น CHAR มากกว่า VARCHAR ในกรณีนี้

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


4
หากคุณเก็บที่อยู่ IP ฉันไม่เห็นเหตุผลที่จะจัดเก็บที่อยู่เหล่านั้นเป็นอย่างอื่นนอกจาก int นั่นคือที่อยู่ IP ทั้งหมด หลายภาษามีฟังก์ชัน ip2int บางประเภท ถ้าคุณต้องการความมั่นใจในการเรียกบรรทัดคำสั่งมันไม่ยากเลยที่จะสร้างโพรซีเดอร์ที่เก็บไว้เพื่อแปลง ABCD: A pow (256,3) + b pow (256,2) + c * 256 + d
atxdba

1
ผิดพลาดมากขึ้นถึงจุดฉันเดา mysql มีฟังก์ชั่น ip2int ของตัวเอง: INET_ATON
atxdba

3
@atxdba: จุดที่คำตอบของฉันคือการใช้ CHAR กับ VARCHAR ฉันเพียงแค่ใช้ IP เป็นตัวอย่างเนื่องจากขนาดของสตริงอักขระนั้นใกล้กับ 15 ดังนั้นการปัดเศษขนาด CHAR ที่เสถียรเพื่อสนับสนุน VARCHAR เป็นเพียงตัวอย่างสำหรับคำถาม ความเห็นของคุณเกี่ยวกับวิธีที่ดีกว่าในการแสดงที่อยู่ IP นั้นค่อนข้างถูกต้องและสมเหตุสมผลที่สุด
RolandoMySQLDBA

CHAR (15) จัดสรร 15 ตัวอักษรไม่ไบต์ สำหรับ utf8 ที่ 45 ไบต์
Rick James

2
แม้ว่านี่จะเป็นคำตอบที่ดีเกี่ยวกับการเปรียบเทียบ CHAR / VARCHAR แต่คำถามก็เกี่ยวกับขนาด VARCHAR ที่แตกต่างกัน
นักสะสม

13

คำตอบนี้ค่อนข้างซับซ้อนจริง ๆ รุ่นสั้น: มีความแตกต่าง

  1. เมื่อสร้างตารางชั่วคราวเพื่อกรองผลลัพธ์ (เช่นGROUP BYคำสั่ง) ความยาวเต็มจะถูกจัดสรร

  2. โปรโตคอลลวด (ส่งแถวไปยังลูกค้า) มีแนวโน้มที่จะจัดสรรความยาวขนาดใหญ่

  3. เอ็นจิ้นการจัดเก็บอาจ / อาจไม่ใช้ varchar

สำหรับ (2) ฉันยอมรับว่า wire protocol ไม่ใช่สิ่งที่ฉันคุ้นเคยอย่างใกล้ชิด แต่คำแนะนำทั่วไปที่นี่คือการลองและใช้ความพยายามอย่างน้อยที่สุดเพื่อคาดเดาความยาว


คุ้มค่าที่จะชี้ให้เห็น MySQL 5.7 สามารถแพ็คค่าในบัฟเฟอร์การเรียงลำดับ (ความยาวผันแปรได้) อธิบายรายละเอียดเพิ่มเติมได้ที่นี่: mysqlserverteam.com/…
Morgan Tocker

9

คำตอบส่วนใหญ่ในหัวข้อนี้มีอายุ 5 ปีซึ่งถูกเขียนก่อน InnoDB และ utf8 เป็นค่าเริ่มต้น ขอผมเริ่มใหม่ ...

เมื่อแบบสอบถามต้องการตารางชั่วคราวภายในจะพยายามใช้MEMORYตาราง แต่ไม่สามารถใช้ MEMORY ได้

  • TEXT/ คอลัมน์เป็นความจริงไม่ได้BLOBTINYTEXT
  • VARCHAR ใหญ่กว่าจำนวนเล็กน้อยอาจเป็น 512 ในเวอร์ชันปัจจุบัน

นอกจากนี้ทราบว่าจะกลายเป็นVARCHARs CHARsดังนั้นVARCHAR(255)ด้วยการCHARACTER SET utf8ขยายเป็น 765 ไบต์โดยไม่คำนึงถึงสิ่งที่อยู่ในคอลัมน์ จากนั้นสิ่งนี้อาจถูกเรียกใช้:

  • หากMEMORYตารางมีขนาดใหญ่กว่าmax_heap_table_size หรือ tmp_table_sizeจะถูกแปลงเป็น MyISAM และอาจกระจายไปยังดิสก์

ดังนั้นVARCHAR(25)มีแนวโน้มที่จะอยู่MEMORYจึงจะเร็วขึ้น (255)ไม่ดีและ(64000)ไม่ดี

(ในอนาคตตารางชั่วคราวอาจจะเป็นInnoDBและส่วนหนึ่งของคำตอบนี้จะต้องแก้ไข)


6

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


นั่นเป็นมุมมองที่สดใหม่มาก หากนี่คือหนังสือที่คุณอ้างถึง ( amazon.com/MySQL-High-Availability-Building-Centers/dp/ ...... ) โปรดใส่หมายเลขหน้าของหนังสือเล่มนี้ในคำตอบของคุณเพราะฉันต้องการอ่าน +1 !!!
RolandoMySQLDBA

Silly me …ประสิทธิภาพสูงไม่พร้อมใช้งาน: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/ ……หมายเลขหน้าเป็น 236/237 มันอธิบายถึงความเอื้ออาทรในการกำหนดคอลัมน์ varchar สามารถไม่ฉลาด โปรดจำไว้ว่าหนังสือเล่มนี้เขียนเมื่อ 5.1 เพิ่งออกมา รุ่นที่สามกำลังจะออกในปีหน้าเพื่อรวมการเปลี่ยนแปลงครั้งใหญ่ทั้งหมดใน 5.5 ดังนั้นอาจจะมีการเปลี่ยนแปลง :)
TechieGurl

หน้า 236 กล่าวถึงการเรียงหน้าของชุดอักขระเฉพาะ นั่นอาจเป็นสิ่งที่น่ารังเกียจสำหรับ VARCHAR บนหน้า 237 การตั้งค่าสำหรับการสื่อสารไคลเอ็นต์ / เซิร์ฟเวอร์พร้อมกับรูปที่ 5-5 ในหน้า 238 แสดงเหตุผลอื่น กระบวนการแปลอักขระตั้งค่ากลับไปกลับมา การผจญภัยที่น่ารังเกียจอีกครั้งสำหรับ VARCHAR
RolandoMySQLDBA

เพื่ออธิบายให้ชัดเจนถึงแม้ว่าส่วนนี้จะไม่พูดตรงๆว่า MySQL จะไปสร้างขนาดเรารู้ว่าเมื่อการดำเนินการต้องใช้ตารางชั่วคราวที่ตารางอยู่ใน MEMORY Engine และที่เก็บประเภทสตริงในการแก้ไขชิ้นเสมอ คำจำกัดความอาจทำให้ตาราง MEMORY temp ที่จำเป็นต้องใช้ไปที่ดิสก์ซึ่งต่างจากการอยู่ใน RAM
TechieGurl

@RolandoMySQLDBA ใช่…ด้วย…การเปรียบเทียบก็กลายเป็นปัจจัยที่นี่ (โดยเฉพาะถ้าคุณใช้ UTF-8 และมีอักขระที่ไม่ใช่ละติน) และมันก็แค่ฆ่าคุณเมื่อจัดการกับตารางหน่วยความจำเครื่องยนต์และนำไปสู่ดิสก์ที่รวดเร็วยิ่งขึ้น
TechieGurl

5

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


3

ให้แน่ใจว่าคุณไม่ได้ออกจากห้อง

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

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

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