กรณีการใช้งานสำหรับเลือก CHAR ผ่าน VARCHAR ใน SQL คืออะไร


270

ฉันตระหนักว่า CHAR แนะนำถ้าค่าทั้งหมดของฉันเป็นความกว้างคงที่ แต่อะไรนะ? ทำไมไม่เพียงแค่เลือก VARCHAR สำหรับฟิลด์ข้อความทั้งหมดเพื่อความปลอดภัย

คำตอบ:


386

โดยทั่วไปรับCHARถ้าแถวทั้งหมดจะต้องใกล้เคียงกับระยะเวลาเดียวกัน เลือกVARCHARเมื่อความยาวแตกต่างกันมาก CHAR อาจเร็วขึ้นอีกเล็กน้อยเนื่องจากแถวทั้งหมดมีความยาวเท่ากัน

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

  • CHAR (6) = 6 ไบต์ (ไม่มีค่าใช้จ่าย)
  • VARCHAR (10) = 8 ไบต์ (2 ไบต์ของค่าใช้จ่าย)
  • CHAR (10) = 10 ไบต์ (4 ไบต์ของค่าใช้จ่าย)

บรรทัดล่างคือCHARสามารถเร็วขึ้นและมีพื้นที่มากขึ้นสำหรับข้อมูลที่มีความยาวเท่ากัน (ภายในความแตกต่างของความยาวอักขระสองตัว)

หมายเหตุ : Microsoft SQL มีค่าใช้จ่าย 2 ไบต์สำหรับ VARCHAR สิ่งนี้อาจแตกต่างจาก DB ถึง DB แต่โดยทั่วไปจะต้องมีค่าใช้จ่ายอย่างน้อย 1 ไบต์เพื่อระบุความยาวหรือ EOL ใน VARCHAR

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


20
อีกเหตุผลหนึ่งคือการแยกหน้าและการแยกส่วน ฉันมีตารางที่มี IDEN PK ซึ่งมีการแยกส่วน 99% เนื่องจากการแยกหน้าในคอลัมน์ varchar ตารางที่แอ็คทีฟมากและโดยธรรมชาติของแอ็พพลิเคชันแถวว่างแถวใหม่จะถูกสร้างขึ้นจากนั้นเติมข้อมูล Char แก้ไขปัญหาการกระจายตัว
paparazzo

12
@Jim McKeeth - การคำนวณเหล่านี้เป็นจริงเฉพาะในกรณีที่คุณใช้ชุดอักขระ latin1 เนื่องจากคนส่วนใหญ่ควรใช้ utf8 วันนี้คอลัมน์ CHAR ของคุณจะใช้พื้นที่โดยเฉลี่ย 3 เท่าเป็น VARCHAR ที่เก็บอักขระส่วนใหญ่ในระนาบหลายภาษาฐาน
Gavin Towey

11
@JimMcKeeth ใช่นั่นถูกต้องแล้ว เนื่องจาก CHAR เป็นความยาวคงที่จึงต้องแก้ไขที่พื้นที่สูงสุดที่สามารถใช้ได้ ใน UTF8 นั่นคือ 3 ไบต์ต่อตัวอักษร สำหรับ varchar สามารถใช้ 1-3 ไบต์ต่อตัวอักษรได้ตามต้องการ นี่คือในคู่มือ MySQL: dev.mysql.com/doc/refman/5.0/en/charset-unicode-utf8.html
Gavin Towey

3
ความแตกต่างกับสตริง FooBar และ varchar (100) vs char (100) คืออะไร? ฉันคิดว่ามันแสดงให้เห็นถึงความแตกต่างที่ดีกว่าใช่ไหม? ไม่มี?
Nenotlep

4
@GavinTowey SQLSERVER ใช้ UCS-2 สำหรับประเภทข้อมูล NCHAR และ NVARCHAR มันมีสองไบต์ต่อตัวอักษรเสมอ
1010

69

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

varcharอีกสิ่งหนึ่งที่ผมไม่เคยเห็นปัญหาประสิทธิภาพการทำงานเพราะมีคนตัดสินใจที่จะไปด้วย คุณจะใช้เวลาในการเขียนโค้ดได้ดีขึ้น (โทรไปยังฐานข้อมูลน้อยลง) และ SQL ที่มีประสิทธิภาพ (ดัชนีทำงานอย่างไร, เครื่องมือเพิ่มประสิทธิภาพจะตัดสินใจexistsได้inอย่างไร

ความคิดสุดท้าย: ฉันได้เห็นปัญหาทุกประเภทเกี่ยวกับการใช้CHARคนมองหา '' เมื่อพวกเขาควรจะมองหา '' หรือคนที่มองหา 'FOO' เมื่อพวกเขาควรจะมองหา 'FOO (กลุ่มของที่นี่) หรือคนที่ไม่ตัดทอนช่องว่างต่อท้ายหรือบั๊กที่มี Powerbuilder เพิ่มช่องว่างได้มากถึง 2,000 ช่องเป็นค่าที่ส่งคืนจากโพรซีเดอร์ Oracle


20
ฉันไม่เห็นด้วยกับย่อหน้าแรกของคุณเนื่องจาก char อาจให้คำแนะนำที่อาจเป็นประโยชน์ต่อเครื่องมือเพิ่มประสิทธิภาพแม้แต่ในอนาคตและอาจช่วยในการสื่อสารจุดประสงค์ของคอลัมน์ แต่ +1 สำหรับย่อหน้าที่สามของคุณ ฉันเกลียดช่องว่างทั้งหมด ฟิลด์ควรเก็บทุกอย่างที่ฉันใส่ไว้โดยไม่มีการเติม [explicative] ทั้งหมด โดยพื้นฐานแล้วฉันแค่ใช้ถ่านถ้าข้อมูลทั้งหมดนั้นมีความยาวเท่ากันไม่มากไม่น้อยไปกว่านี้ตลอดไป แน่นอนว่าเป็นของหายากและมักจะเป็นถ่าน (1)
Jeffrey L Whitledge

char ยังให้คำแนะนำแก่นักวิเคราะห์และนักพัฒนา ... สิ่งนี้คือ x จำนวนตัวอักษร .... ถ้าพวกเขาคิดที่จะทำให้เป็นอนุกรมในรูปแบบอื่น ๆ นั่นอาจเป็นประโยชน์ (ฉันถูกบังคับให้เก็บ mum5 checksum ใน char ใน mssql ที่ไม่มีประเภท uuid ... และฉันไม่ต้องการอะไรเลย <32 ไบต์ ... ใส่ข้อ จำกัด ลงในคอลัมน์ด้วย)
joefromct

31

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


หรือรหัสประเทศ - สามารถช่วยแยกแยะความแตกต่างระหว่างการใช้ตัวย่อรหัสประเทศ 2 หรือ 3 ตัว
แดนฟิลด์

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

18

Char เร็วขึ้นเล็กน้อยดังนั้นหากคุณมีคอลัมน์ที่คุณรู้ว่ามีความยาวพอสมควรให้ใช้ถ่าน ตัวอย่างเช่นการจัดเก็บ (M) ale / (F) emale / (U) ไม่ทราบเพศหรือ 2 ตัวอักษรสำหรับรัฐของสหรัฐอเมริกา


4
ไม่แน่ใจว่าเป็นคำตอบที่ดีมากเนื่องจาก ENUM มักจะมีเหตุผลมากกว่านี้ถึงแม้ว่าฉันไม่แน่ใจว่าประเภทนั้นรองรับ (นอก MySQL)
บ๊อบบี้แจ็ค

ดูเหมือนว่าชุดของรัฐไม่จำเป็นต้องไม่เปลี่ยนรูปดังนั้น char (2) จึงดูเหมาะสมกว่า enum
Kearns

1
@ บ๊อบบี้แจ็ค - ฉันไม่ทราบรายละเอียดที่เฉพาะเจาะจงของการใช้งาน enum ของ SQL แต่จำไว้ว่า enum ที่จัดเก็บเป็นจำนวนเต็ม 4 ไบต์อาจต้องใช้พื้นที่มากกว่าคอลัมน์ถ่าน (1) หรือถ่าน (2) ด้วย ข้อมูลเดียวกัน มีความรู้สึกที่ enums มีเหตุผลมากกว่าในแง่ของการตีความของพวกเขาและที่อาจจะน่าสนใจ แต่ทุกอย่างในระบบ RDBMS เป็นนามธรรมในระดับหนึ่งและอยู่ภายใต้ภาคที่กำหนดไว้สำหรับตาราง
Jeffrey L Whitledge

4
ตัวอย่างที่ไม่ดี ENUM ดีที่สุดสำหรับกรณีนั้น ตัวอย่างที่ดีกว่าคือรหัสสนามบิน IATA 3 ตัว
Andrew G. Johnson

5
@Andrew ไม่ใช่ประเภทข้อมูล ENUM ที่สนับสนุนทั้งหมด ตัวอย่างเช่น MSSQLServer ไม่ นอกจากนี้ ENUM ซึ่งจัดเก็บเป็น int ใช้เวลา 4 ไบต์ CHAR (1) ใช้เวลา 1 ไบต์และ NCHAR (1) ใช้เวลา 2 ไบต์
Jarrett Meyer

17

NChar หรือ Char มีประสิทธิภาพดีกว่าหรือไม่?

เป็นคำถามที่ดีมาก คำตอบง่ายๆคือใช่ในบางสถานการณ์ เรามาดูกันว่าสิ่งนี้สามารถอธิบายได้หรือไม่

เห็นได้ชัดว่าเราทุกคนรู้ว่าถ้าฉันสร้างตารางที่มีคอลัมน์ของ varchar (255) (ลองเรียกคอลัมน์นี้ว่า myColumn) และแทรกหนึ่งล้านแถว แต่ใส่เพียงไม่กี่ตัวอักษรลงใน myColumn สำหรับแต่ละแถวตารางจะเล็กกว่ามาก จำนวนหน้าข้อมูลที่เอ็นจิ้นการจัดเก็บที่ต้องการ) มากกว่าถ้าฉันสร้าง myColumn เป็น char (255) ทุกครั้งที่ฉันทำการดำเนินการ (DML) บนตารางนั้นและขอแถวจำนวนมากมันจะเร็วขึ้นเมื่อ myColumn เป็น varchar เพราะฉันไม่ต้องย้ายไปรอบ ๆ ช่องว่าง "พิเศษ" ทั้งหมดในตอนท้าย ย้ายเช่นเดียวกับเมื่อ SQL Server ทำการเรียงลำดับภายในเช่นระหว่างการดำเนินการที่แตกต่างกันหรือการรวมหรือถ้ามันเลือกผสานระหว่างมันเป็นแผนแบบสอบถาม ฯลฯ

แต่มีค่าใช้จ่ายในการใช้ varchar SQL Server จะต้องใช้ตัวบ่งชี้ที่สองไบต์ (ค่าใช้จ่าย) เพื่อ, ในแต่ละแถว, เพื่อทราบจำนวนไบต์ที่ myColumn ของแถวใดแถวหนึ่งมีอยู่ในนั้น ไม่ใช่ 2 ไบต์พิเศษที่นำเสนอปัญหา แต่ก็ต้อง "ถอดรหัส" ความยาวของข้อมูลใน myColumn ทุกแถว

จากประสบการณ์ของฉันมันมีเหตุผลที่จะใช้ถ่านแทน varchar ในคอลัมน์ที่จะเข้าร่วมในแบบสอบถาม ตัวอย่างเช่นคีย์หลักของตารางหรือคอลัมน์อื่น ๆ ที่จะได้รับการจัดทำดัชนี หมายเลขลูกค้าในตารางข้อมูลประชากรหรือรหัสประจำตัวบนตารางถอดรหัสหรืออาจเป็นหมายเลขสั่งซื้อบนตารางคำสั่งซื้อ โดยการใช้ถ่านเคียวรีเอ็นจินสามารถดำเนินการเข้าร่วมได้เร็วขึ้นเนื่องจากมันสามารถทำเลขคณิตตัวชี้แบบตรง (กำหนดขึ้น) แทนที่จะต้องย้ายตัวชี้เป็นจำนวนไบต์ที่แปรผันตามที่อ่านหน้า ฉันรู้ว่าฉันอาจสูญเสียคุณในประโยคสุดท้าย ตัวเชื่อมใน SQL Server อิงตามแนวคิดของ "ภาคแสดง" เพรดิเคตเป็นเงื่อนไข ตัวอย่างเช่น myColumn = 1 หรือ OrderNumber <500

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

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

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

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

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

โปรดทราบว่าถ่านสามารถทำให้ฐานข้อมูลของคุณมีขนาดใหญ่ขึ้น แต่เครื่องมือสำรองส่วนใหญ่มีการบีบอัดข้อมูลดังนั้นการสำรองข้อมูลของคุณมักจะมีขนาดใกล้เคียงกับถ้าคุณใช้ varchar ตัวอย่างเช่น LiteSpeed ​​หรือ RedGate SQL Backup

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

create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )

insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)

create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))

SELECT * from vwStagingTable

นี่เจ๋งเพราะข้อมูลของฉันใช้พื้นที่น้อยกว่าเพราะใช้ varchar แต่เมื่อฉันใช้ DTS หรือ SSIS หรือเพียงแค่ตัดและวางจาก SSMS ไปยัง Notepad ฉันสามารถใช้มุมมองและรับจำนวนช่องว่างที่ถูกต้อง ใน DTS เราเคยมีคุณสมบัติที่เรียกว่า, ฉันลืมฉันคิดว่ามันถูกเรียกว่า "คอลัมน์แนะนำ" หรืออะไรบางอย่าง ใน SSIS คุณไม่สามารถทำเช่นนั้นได้อีกต่อไปคุณต้องกำหนดตัวจัดการการเชื่อมต่อไฟล์แฟล็ต แต่เนื่องจากคุณมีการตั้งค่ามุมมอง SSIS สามารถทราบความกว้างของแต่ละคอลัมน์และสามารถประหยัดเวลาได้มากเมื่อสร้างงานการรับส่งข้อมูล

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

หวังว่าจะช่วย เจฟฟ์


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

9

มีประโยชน์ด้านประสิทธิภาพ แต่นี่คือสิ่งที่ไม่ได้กล่าวถึง: การย้ายข้อมูลแถว ด้วยถ่านคุณจองพื้นที่ทั้งหมดล่วงหน้าดังนั้นสมมติว่าคุณมีถ่าน (1,000) และคุณเก็บอักขระ 10 ตัวคุณจะใช้พื้นที่ทั้งหมด 1,000 หลังคา ใน varchar2 (1,000) คุณจะใช้เพียง 10 ตัวอักษร ปัญหาเกิดขึ้นเมื่อคุณแก้ไขข้อมูล สมมติว่าคุณอัปเดตคอลัมน์ให้มีอักขระ 900 ตัว เป็นไปได้ว่าพื้นที่สำหรับขยาย varchar ไม่พร้อมใช้งานในบล็อกปัจจุบัน ในกรณีนั้นเอ็นจิน DB ต้องย้ายแถวไปยังบล็อกอื่นและสร้างตัวชี้ในบล็อกดั้งเดิมไปยังแถวใหม่ในบล็อกใหม่ หากต้องการอ่านข้อมูลนี้เอ็นจิน DB จะต้องอ่าน 2 บล็อก
ไม่มีใครพูดได้อย่างมั่นใจว่าวาร์ชาหรือชาร์จะดีกว่า มีพื้นที่สำหรับการแลกเปลี่ยนเวลาและการพิจารณาว่าข้อมูลจะได้รับการปรับปรุงโดยเฉพาะอย่างยิ่งหากมีโอกาสที่จะเติบโต


ฉันคิดว่าคุณมีการพิมพ์ผิดในโพสต์ของคุณ - ไม่ควร varchar2 (1,000) เป็น CHAR (1,000)?
Matt Rogish

8

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

ie - หากคุณมีฟิลด์สถานะตัวอักษร 2 ตัวให้ใช้ CHAR (2) หากคุณมีฟิลด์ที่มีชื่อสถานะจริงให้ใช้ VARCHAR


8

ฉันจะเลือก varchar เว้นเสียแต่ว่าคอลัมน์จะเก็บค่าคงที่เช่นรหัสรัฐของสหรัฐอเมริกา - ซึ่งจะมีความยาว 2 ตัวอักษรเสมอและรายการรหัสสหรัฐอเมริกาที่ถูกต้องจะไม่เปลี่ยนแปลงบ่อย :)

ในกรณีอื่น ๆ เช่นการจัดเก็บรหัสผ่านที่แฮช (ซึ่งมีความยาวคงที่) ฉันจะเลือก varchar

ทำไม - คอลัมน์ประเภท char มีการเติมเต็มช่องว่างเสมอซึ่งทำให้คอลัมน์my_columnถูกกำหนดเป็นอักขระ char (5) ที่มีค่า 'ABC' อยู่ในการเปรียบเทียบ:

my_column = 'ABC' -- my_column stores 'ABC  ' value which is different then 'ABC'

เท็จ

คุณลักษณะนี้อาจนำไปสู่ข้อบกพร่องที่น่ารำคาญมากมายระหว่างการพัฒนาและทำให้การทดสอบหนักขึ้น


1
อย่างน้อยในเซิร์ฟเวอร์ MSSQL, 'abc' = 'abc' ฉันไม่เคยคิดมาก่อนเลยว่าฉันจะชอบหรือไม่ชอบคุณลักษณะนั้น ....
357 Mark

อ่านดีเกี่ยวกับ padding ของ char ที่นี่Padding
Edward

6

CHAR ใช้พื้นที่เก็บข้อมูลน้อยกว่า VARCHAR หากค่าข้อมูลทั้งหมดของคุณในฟิลด์นั้นมีความยาวเท่ากัน ตอนนี้บางทีในปี 2009 ฐานข้อมูล 800GB จะเหมือนกันสำหรับทุก intents และวัตถุประสงค์เป็น 810GB ถ้าคุณแปลง VARCHARs เป็น CHARs แต่สำหรับสตริงสั้น ๆ (1 หรือ 2 ตัวอักษร) CHAR ยังคงเป็น "แนวปฏิบัติที่ดีที่สุด" ในอุตสาหกรรม

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

แต่มันเป็นข้อโต้แย้งที่น่าสนใจและเมื่อฐานข้อมูลดีขึ้นเรื่อย ๆ มันอาจจะเป็นที่ถกเถียงกันอยู่ว่า CHAR กับ VARCHAR มีความเกี่ยวข้องน้อย


4

ฉันยืนตามความคิดเห็นของ Jim McKeeth

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

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

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

จำคำพูดที่ชาญฉลาดของ Djikstra การเพิ่มประสิทธิภาพก่อนกำหนดเป็นรากฐานของความชั่วร้ายทั้งหมด


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

อีธานถูกต้องทั้งหมด สิ่งนี้ขึ้นอยู่กับการใช้งานที่คุณใช้โดยไม่มีการอ้างอิงถึงจริง (ผลิตภัณฑ์เวอร์ชัน) มันไม่มีประโยชน์อย่างสมบูรณ์
David Schmitt

เมื่อคุณอัปเดตCHARคอลัมน์ดัชนีจำเป็นต้องได้รับการอัปเดตเช่นกัน ไม่มีความแตกต่างในการอัปเดต VARCHAR หรือคอลัมน์ CHAR ในเรื่องนั้น คิดเกี่ยวกับการปรับปรุงการFOO BAR
a_horse_with_no_name

4

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


3

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

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

ฉันมักจะใช้ VarChar และมักจะทำให้มันใหญ่กว่าที่ฉันต้องการอย่างมาก เช่น. 50 สำหรับชื่ออย่างที่คุณพูดทำไมไม่เพียง แต่จะปลอดภัย


3

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

ดังนั้นนี่คือปัญหาบางส่วนที่คุณจะพบ:

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

ทีนี้สมมติว่าคุณมีตัวอย่างที่เป็นแก่นสารของฟิลด์ char ของอักขระเพียงตัวเดียว แต่ฟิลด์นั้นเป็นตัวเลือก หากใครบางคนผ่านสตริงว่างไปยังเขตข้อมูลนั้นมันจะกลายเป็นหนึ่งช่อง ดังนั้นเมื่อแอปพลิเคชัน / กระบวนการอื่นสอบถามพวกเขาจะได้รับหนึ่งช่องว่างถ้าไม่ใช้ rtrim เรามีเอกสาร xml, ไฟล์และโปรแกรมอื่น ๆ , แสดงเพียงหนึ่งช่องว่าง, ในฟิลด์ตัวเลือกและแบ่งสิ่งต่างๆ

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

ชื่อ | เพศ | เมือง

Bob || ลอสแองเจลิส

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

ชื่อ | เมือง

บ๊อบ | แอตเทิล

ตอนนี้เนื่องจากไม่รวมเพศฉันจะใช้ null Varchars สนับสนุนสิ่งนี้โดยไม่มีปัญหา

Char ในทางกลับกันจะแตกต่างกัน คุณต้องส่งค่าว่างเสมอ หากคุณเคยส่งสตริงว่างคุณจะพบกับฟิลด์ที่มีช่องว่างอยู่

ฉันสามารถทำต่อไปเรื่อย ๆ กับข้อบกพร่องทั้งหมดที่ฉันต้องแก้ไขจากตัวอักษรและในการพัฒนาประมาณ 20 ปี


2

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


2

มันเป็นพื้นที่คลาสสิกกับการแลกเปลี่ยนประสิทธิภาพ

ใน MS SQL 2005 Varchar (หรือ NVarchar สำหรับ lanuagues ที่ต้องการสองไบต์ต่ออักขระเช่นจีน) เป็นความยาวผันแปร หากคุณเพิ่มลงในแถวหลังจากที่ถูกเขียนลงในฮาร์ดดิสก์แล้วมันจะค้นหาข้อมูลในตำแหน่งที่ไม่เกี่ยวข้องกับแถวต้นฉบับและนำไปสู่การแตกไฟล์ข้อมูลของคุณ สิ่งนี้จะส่งผลต่อประสิทธิภาพ

ดังนั้นหากพื้นที่ไม่ใช่ปัญหาแล้ว Char จะดีกว่าสำหรับประสิทธิภาพการทำงาน แต่ถ้าคุณต้องการลดขนาดฐานข้อมูลลง varchars จะดีกว่า


2

การกระจายตัวของ Char จองพื้นที่และ VarChar ไม่ได้ สามารถแบ่งหน้าได้เพื่อรองรับการอัปเดตเป็น varchar


เนื่องจากปัจจัยอื่น ๆ การแบ่งหน้าอาจเกิดขึ้นเมื่ออัปเดตCHARคอลัมน์
Rick James

1

เมื่อใช้ค่า varchar SQL Server ต้องการ 2 ไบต์ต่อแถวเพิ่มเติมเพื่อเก็บข้อมูลบางอย่างเกี่ยวกับคอลัมน์นั้นในขณะที่ถ้าคุณใช้ถ่านไม่จำเป็นต้องทำเช่นนั้นเว้นแต่คุณจะ


0

ในฐานข้อมูล SQL บางตัว VARCHAR จะถูกย่อขนาดให้ใหญ่ที่สุดเพื่อปรับอ็อฟเซ็ตให้เหมาะสมนี่คือเพื่อเพิ่มความเร็วในการสแกนตารางและดัชนี

ด้วยเหตุนี้คุณจึงไม่ต้องประหยัดพื้นที่โดยใช้ VARCHAR (200) เทียบกับ CHAR (200)


3
ฐานข้อมูลใดที่ใช้ VARCHAR แบบนั้น?
Troels Arvin

5
อย่างจริงจังฐานข้อมูลใดที่ใช้วิธีการนั้น สิ่งที่คุณอธิบายตามปกติจะใช้กับ CHAR ไม่ใช่ VARCHAR
ริชาร์ดSimões

mysql จะแปลง varchar เป็น chars หากมี char และ varchar ในตารางเดียวกัน
Malfist

การตีความความคิดเห็น MySQL ของฉันคือสิ่งนี้ไม่ได้ใช้กับการจัดเก็บตารางหลัก แต่อาจเกี่ยวข้องกับตารางชั่วคราวเช่น สำหรับการจัดกลุ่ม / การเรียงลำดับข้อมูล dev.mysql.com/doc/refman/8.0/en/char.html stackoverflow.com/questions/262238/…
โทมัส W

0

การใช้ CHAR (NCHAR) และ VARCHAR (NVARCHAR) ทำให้เกิดความแตกต่างในวิธีที่เซิร์ฟเวอร์ฐานข้อมูลเก็บข้อมูล คนแรกแนะนำช่องว่างต่อท้าย; ฉันพบปัญหาเมื่อใช้กับตัวดำเนินการ LIKE ในฟังก์ชัน SQL SERVER ดังนั้นฉันต้องทำให้ปลอดภัยโดยใช้ VARCHAR (NVARCHAR) ตลอดเวลา

ตัวอย่างเช่นถ้าเรามีตารางTEST (ID INT, CHAR สถานะ (1))และคุณเขียนฟังก์ชั่นเพื่อแสดงรายการระเบียนทั้งหมดที่มีค่าเฉพาะบางอย่างดังต่อไปนี้:

CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'

ในฟังก์ชั่นนี้เราคาดหวังว่าเมื่อเราใส่พารามิเตอร์เริ่มต้นฟังก์ชั่นจะกลับแถวทั้งหมด แต่ในความเป็นจริงมันไม่ได้ เปลี่ยนชนิดข้อมูล @Status เป็น VARCHAR จะแก้ไขปัญหา


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