อะไรคือความแตกต่างของประสิทธิภาพหลักระหว่างชนิดข้อมูล varchar และ nvarchar SQL Server?


236

ฉันกำลังทำงานบนฐานข้อมูลสำหรับเว็บแอปเล็ก ๆ SQL Server 2005ที่โรงเรียนของฉันโดยใช้
ฉันเห็นโรงเรียนแห่งความคิดสองแห่งเกี่ยวกับเรื่องvarcharvs nvarchar:

  1. ใช้จนกว่าคุณจะจัดการกับข้อมูลจำนวนมากสากลแล้วการใช้งานvarcharnvarchar
  2. เพียงใช้nvarcharกับทุกสิ่ง

ฉันเริ่มเห็นข้อดีของการดู 2 ฉันรู้ว่า nvarchar ใช้พื้นที่มากเป็นสองเท่า แต่นั่นก็ไม่ได้เป็นเรื่องใหญ่เพราะนี่จะเก็บข้อมูลสำหรับนักเรียนสองสามร้อยคนเท่านั้น สำหรับฉันดูเหมือนว่ามันจะง่ายที่สุดที่จะไม่กังวลเกี่ยวกับมันและเพียงแค่อนุญาตให้ทุกอย่างใช้ nvarchar หรือมีบางอย่างที่ฉันขาดหายไป?


คำถามที่คล้ายกันที่นี่: stackoverflow.com/questions/312170/…แก้ไขโดย le dorfier: ซึ่งน่าสนใจมาถึงข้อสรุปตรงข้าม
Booji Boy

6
อ้างอิงหัวข้อที่กว้างขวางมากขึ้นซึ่งมาถึงข้อสรุปตรงข้าม stackoverflow.com/questions/312170/…
dkretz

2
Jason: ฉันหวังว่านี่ไม่ใช่คำขอที่ไม่เหมาะสม แต่คุณสามารถพิจารณาเปลี่ยนคำตอบที่ยอมรับให้กับgbn ได้ไหม คำตอบของ JoeBarone ผิดอย่างน่ากลัวด้วยเหตุผลหลายประการ การที่มันเป็น "ยอมรับ" ทำให้เข้าใจผิดกลายเป็นการเลือกที่ไม่ดี ไม่จำเป็นและสิ้นเปลือง "ใช้เสมอNVARCHAR" และอาจมีผลเสียต่อประสิทธิภาพและต้นทุนฮาร์ดแวร์ / งบประมาณ ไม่กี่แถวแม้แต่สองสามพันคนก็ไม่สำคัญ แต่ระบบเติบโตอย่างรวดเร็วมากกว่าที่ผู้คนคาดหวังดังนั้นคำตอบที่ได้รับการยอมรับในปัจจุบันคือการก่อความเสียหายให้กับชุมชน ขอบคุณ.
โซโลมอน Rutzky

คำตอบ:


140

ใช้ nvarchar เสมอ

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

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


4
มันยากที่จะย้อนกลับไปและเพิ่มการสนับสนุนสำหรับข้อความ / ข้อความหลายภาษาโซนเวลาหน่วยการวัดและสกุลเงินดังนั้นทุกคนจะต้องใส่รหัสเหล่านี้ในแอปพลิเคชันของพวกเขาเสมอตั้งแต่วันแรกเสมอ แอป)!
กม.

82
ขนาดดัชนีการใช้หน่วยความจำเป็นต้น ฉันคิดว่าคุณใช้ int เสมอเมื่อคุณสามารถใช้จิ๋วจินท์ด้วยเช่นกัน "ในกรณี"?
gbn

99
เขียนโค้ด / วางแผนเว็บไซต์ที่พูดได้หลายภาษาเสมอ (เมื่อคุณไม่มีปัญหาเรื่องหมึกที่คุณจำเป็นต้องใช้) เป็นเหมือนการบอกคนหนุ่มสาวทุกคนพวกเขาควรซื้อ 8 ที่นั่งขนาดใหญ่ SUV ที่ใช้แก๊สโซเซสำหรับรถคันแรก ... หลังจากทั้งหมด พวกเขาอาจจะแต่งงานสักวันและอาจมีลูก 6 คน ฉันอยากสนุกกับประสิทธิภาพและประสิทธิภาพในขณะที่ฉันสามารถและจ่ายราคาสำหรับการอัพเกรดเมื่อ / ถ้าฉันต้องการมัน
EJ Brennan

4
@cbmeeks: ฉันทำไม่ได้สำหรับสิ่งที่ผมไม่ทราบ แต่ถ้าคุณสามารถใช้งานได้โดยไม่มีผลกระทบต่อประสิทธิภาพที่เห็นได้ชัดเจนฐานข้อมูลของคุณจะไม่ใหญ่พอสำหรับเรื่องนี้ ...
gbn

60
โดยปกติเมื่อผู้คนเริ่มต้นคำตอบด้วยคำว่า "เสมอ" คุณควรละเว้นทุกสิ่งที่เกิดขึ้นหลังจากนั้น (โปรดสังเกตว่าฉันเริ่มต้นข้อความนั้นด้วยคำว่า "มักจะ" :)
แบรนดอนมัวร์

226

พื้นที่ดิสก์ไม่ใช่ปัญหา ... แต่จะมีหน่วยความจำและประสิทธิภาพการทำงาน อ่านหน้าเป็นสองเท่าขนาดดัชนีสองเท่า LIKE ที่แปลกและพฤติกรรมคงที่ = ฯลฯ

คุณต้องการเก็บสคริปต์ภาษาจีน ฯลฯ หรือไม่? ใช่หรือไม่...

และจาก MS BOL "การจัดเก็บและประสิทธิภาพของ Unicode "

แก้ไข :

คำถาม SO ล่าสุดที่เน้นถึงประสิทธิภาพของ nvarchar ที่ไม่ดีสามารถ ...

SQL Server ใช้ CPU สูงเมื่อค้นหาภายในสตริง nvarchar


19
+1 หากแอปของคุณเป็นสากลคุณจะมีปัญหาอื่น ๆ อีกมากมายที่ต้องกังวลเกี่ยวกับการค้นหา / แทนที่ nvarchar: ข้อความ / ข้อความหลายภาษาโซนเวลาหน่วยวัดและสกุลเงิน
KM

2
แต่ถ้าคุณต้องการเก็บชื่อต่างประเทศบางครั้งเช่นJoséหรือBjørn
Qwertie

7
@Qwertie: จากนั้นคุณใช้ nvarchar สิ่งที่คุณไม่ได้ใช้มันไม่จำเป็น ชื่อเหล่านั้น 2 ชื่อเหมาะสมกับ varchar อย่างไรก็ตาม IIRC
gbn

6
การบอกว่าพื้นที่ดิสก์ไม่ใช่ปัญหาสำหรับทุกคน เราใช้ nvarchar อย่างไร้เดียงสาโดยไม่จำเป็นในแอปพลิเคชันธนาคารขนาดใหญ่ที่มีบันทึกหลายพันล้านรายการที่จัดเก็บในช่วงหลายปีที่ผ่านมา ด้วยพื้นที่เก็บข้อมูลแบบ SAN ที่มีราคาแพงพร้อมการทำซ้ำการสำรองข้อมูลและการกู้คืนระบบจึงสามารถแปลค่าใช้จ่ายเป็นล้านดอลลาร์สำหรับ nvarchar vs varchar ไม่ต้องพูดถึงมีผลกระทบต่อประสิทธิภาพการทำงานขนาดใหญ่ (100%) ที่ต้องอ่านสองเท่าของจำนวนไบต์จากดิสก์สำหรับการอ่านทุกครั้ง
codemonkey

2
@codemonkey และอื่น ๆ : ฉันทำสิ่งที่ฉันสามารถทำได้เพื่อจัดการกับปัญหาการสูญเสียพื้นที่แบบองค์รวมในบทความต่อไปนี้: ดิสก์มีราคาถูก! ORLY? (จำเป็นต้องลงทะเบียนฟรี) บทความนี้มีวัตถุประสงค์เพื่อช่วยป้องกันสถานการณ์ที่ codemonkey เข้ามาเกี่ยวข้องกับการจัดเก็บข้อมูลระดับองค์กรราคาแพง
โซโลมอน Rutzky

59

คงเส้นคงวา! การเข้าร่วม VARCHAR ไปยัง NVARCHAR นั้นได้รับความนิยมอย่างมาก


115
หากคุณกำลังเข้าร่วมในฟิลด์ตัวอักษรฐานข้อมูลของคุณอาจมีปัญหาที่แย่กว่าการใช้ nvarchar หรือ varchar โดยทั่วไปแล้ว
แบรนดอนมัวร์

@Thomas ฮาร์ลานทดสอบอย่างง่ายแสดงให้เห็นกับผมว่าไม่มีความแตกต่างที่มีตัวตนระหว่างการเข้าร่วมnvarcharที่จะvarcharเทียบกับการแปลงnvarcharไปและเข้าร่วมในการvarchar varcharเว้นแต่คุณจะหมายถึงความสอดคล้องในประเภทข้อมูลคอลัมน์ไม่ได้เข้าร่วม
ajeh

1
@ajeh และ Thomas: 1) การทดสอบ "ง่าย" มักทำให้เข้าใจผิดเนื่องจากไม่ครอบคลุมการเปลี่ยนแปลงที่ทำให้เกิดความแตกต่างในพฤติกรรม 2) หากพบว่ามีการใช้งานจำนวนมากเมื่อมีการผสมVARCHARและNVARCHARนั่นอาจเนื่องมาจากการจัดทำดัชนีของVARCHARคอลัมน์พร้อมกับประเภทของการเปรียบเทียบที่ใช้สำหรับคอลัมน์นั้น (และด้วยเหตุนี้ดัชนี) ฉันครอบคลุมหัวข้อนี้ในรายละเอียดในบล็อกโพสต์ต่อไปนี้: ผลกระทบต่อดัชนีเมื่อผสม VARCHAR และ NVARCHAR ประเภท
โซโลมอน Rutzky

44

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

ฉันจะไม่มีกฎ "nvarchar" ที่ยากและรวดเร็วเพราะมันอาจเป็นการสิ้นเปลืองอย่างสมบูรณ์ในหลาย ๆ สถานการณ์ - โดยเฉพาะ ETL จาก ASCII / EBCDIC หรือตัวระบุและคอลัมน์รหัสซึ่งมักจะเป็นกุญแจและกุญแจต่างประเทศ

ในอีกทางหนึ่งมีหลายกรณีของคอลัมน์ที่ฉันจะแน่ใจว่าถามคำถามนี้ก่อนและถ้าฉันไม่ได้รับคำตอบที่รวดเร็วและรวดเร็วฉันจะทำให้คอลัมน์ nvarchar


26

ฉันลังเลที่จะเพิ่มอีกคำตอบที่นี่เนื่องจากมีอยู่ไม่กี่อย่าง แต่ต้องมีบางจุดที่ยังไม่ได้ทำหรือไม่ได้ทำอย่างชัดเจน

แม่: Do ไม่NVARCHARเคยใช้ นั่นเป็นทัศนคติที่อันตรายและมักมีค่าใช้จ่ายสูง และไม่ควรพูดว่า " ไม่ใช้เคอร์เซอร์" เพราะบางครั้งวิธีที่มีประสิทธิภาพมากที่สุดในการแก้ปัญหาเฉพาะและการทำงานร่วมกันแบบWHILEวนรอบมักจะช้ากว่าเคอร์เซอร์ที่ทำอย่างถูกต้อง

ครั้งเดียวที่คุณควรใช้คำว่า "เสมอ" คือเมื่อแนะนำให้ "ทำสิ่งที่ดีที่สุดสำหรับสถานการณ์เสมอ" ได้รับซึ่งมักจะยากที่จะกำหนดโดยเฉพาะอย่างยิ่งเมื่อพยายามที่จะรักษาสมดุลกำไรระยะสั้นในการพัฒนา (ผู้จัดการ: "เราต้องการคุณสมบัตินี้ - ซึ่งคุณไม่เคยรู้มาก่อนจนกระทั่งตอนนี้ - เมื่อสัปดาห์ที่แล้ว!") ด้วยความยาว ค่าใช้จ่ายในการบำรุงรักษาระยะยาว (ผู้จัดการที่กดดันทีมในตอนแรกเพื่อทำโครงการ 3 เดือนในระยะเวลา 3 สัปดาห์: "ทำไมเราถึงมีปัญหาด้านประสิทธิภาพเหล่านี้เราจะทำ X ที่ไม่มีความยืดหยุ่นได้อย่างไร? การวิ่งหนึ่งหรือสองเพื่อแก้ไขปัญหานี้เราสามารถทำอะไรได้ภายในหนึ่งสัปดาห์เพื่อให้เราสามารถกลับไปที่รายการที่เราจัดลำดับความสำคัญได้และเราต้องใช้เวลามากขึ้นในการออกแบบดังนั้นสิ่งนี้จะไม่เกิดขึ้น! ")

ที่สอง:คำตอบของ @ gbn สัมผัสกับประเด็นสำคัญที่ควรพิจารณาเมื่อตัดสินใจสร้างแบบจำลองข้อมูลบางอย่างเมื่อเส้นทางไม่ชัดเจน 100% แต่ยังมีสิ่งที่ต้องพิจารณาอีกมาก:

  • ขนาดของไฟล์บันทึกธุรกรรม
  • เวลาที่ใช้ในการทำซ้ำ (ถ้าใช้การจำลองแบบ)
  • เวลาที่ใช้กับ ETL (ถ้า ETLing)
  • เวลาที่ใช้ในการจัดส่งบันทึกไปยังระบบระยะไกลและเรียกคืน (ถ้าใช้ Log Shipping)
  • ขนาดของการสำรองข้อมูล
  • ระยะเวลาที่ใช้ในการสำรองข้อมูลให้เสร็จสมบูรณ์
  • ระยะเวลาที่ใช้ในการทำการกู้คืน (ซึ่งอาจมีความสำคัญในบางวัน ;-)
  • ขนาดที่จำเป็นสำหรับ tempdb
  • ประสิทธิภาพของทริกเกอร์ (สำหรับแทรกและลบตารางที่เก็บไว้ใน tempdb)
  • ประสิทธิภาพของการกำหนดเวอร์ชันของแถว (หากใช้ SNAPSHOT ISOLATION เนื่องจากที่เก็บรุ่นอยู่ใน tempdb)
  • ความสามารถในการรับพื้นที่ดิสก์ใหม่เมื่อ CFO กล่าวว่าพวกเขาเพิ่งใช้จ่าย $ 1 ล้านใน SAN ปีที่แล้วดังนั้นพวกเขาจะไม่อนุญาตอีก $ 250k สำหรับการจัดเก็บเพิ่มเติม
  • ระยะเวลาที่ใช้ในการดำเนินการ INSERT และ UPDATE
  • ระยะเวลาที่ใช้ในการบำรุงรักษาดัชนี
  • ฯลฯ ฯลฯ ฯลฯ

การสูญเสียพื้นที่มีผลกระทบน้ำตกขนาดใหญ่ในระบบทั้งหมด ฉันเขียนบทความที่มีรายละเอียดชัดเจนในหัวข้อนี้: Disk is Cheap! ORLY? (ต้องลงทะเบียนฟรีขออภัยฉันไม่ได้ควบคุมนโยบายนั้น)

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

  • เขตข้อมูลสำหรับชื่อนักศึกษาและ / หรือคณะอาจเป็นNVARCHARเพราะเมื่อเวลาผ่านไปมีแนวโน้มว่าชื่อจากวัฒนธรรมอื่น ๆ จะปรากฏขึ้นในสถานที่เหล่านั้น
  • แต่สำหรับที่อยู่และชื่อเมือง? วัตถุประสงค์ของแอพไม่ได้ระบุไว้ (จะเป็นประโยชน์) แต่สมมติว่ามีการบันทึกที่อยู่ (ถ้ามี) เกี่ยวข้องกับพื้นที่ทางภูมิศาสตร์ที่เฉพาะเจาะจง (เช่นภาษา / วัฒนธรรมเดียว) จากนั้นใช้VARCHARกับหน้ารหัสที่เหมาะสม (ซึ่ง ถูกกำหนดจากการจัดเรียงของฟิลด์)
  • หากการจัดเก็บรหัสรัฐและ / หรือประเทศ ISO (ไม่จำเป็นต้องจัดเก็บINT/ TINYINTเนื่องจากรหัส ISO นั้นมีความยาวคงที่มนุษย์สามารถอ่านได้และเป็นมาตรฐาน :) ใช้CHAR(2)สำหรับรหัสตัวอักษรสองตัวและCHAR(3)หากใช้รหัสตัวอักษร 3 ตัว Latin1_General_100_BIN2และพิจารณาใช้การเปรียบเทียบไบนารีเช่น
  • หากการจัดเก็บรหัสไปรษณีย์ (เช่นรหัสไปรษณีย์) ให้ใช้VARCHARเนื่องจากเป็นมาตรฐานสากลที่จะไม่ใช้จดหมายใด ๆ นอก AZ และใช่ยังคงใช้งานVARCHARได้แม้ว่าจะจัดเก็บรหัสไปรษณีย์ของสหรัฐฯเท่านั้นและไม่ใช่ INT เนื่องจากรหัสไปรษณีย์ไม่ใช่ตัวเลขพวกเขาเป็นสตริงและบางคนมีผู้นำ "0" Latin1_General_100_BIN2และพิจารณาใช้การเปรียบเทียบไบนารีเช่น
  • หากการจัดเก็บที่อยู่อีเมลและ / หรือ URL ให้ใช้NVARCHARเนื่องจากทั้งคู่สามารถมีอักขระ Unicode ได้แล้ว
  • และอื่น ๆ ....

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

  1. ถ้าคุณใช้ SQL Server 2008 - 2016 RTM และอยู่ใน Enterprise Edition หรือถ้าใช้ SQL Server 2016 SP1 (ซึ่งทำให้การบีบอัดข้อมูลพร้อมใช้งานในทุกรุ่น) หรือใหม่กว่าคุณสามารถเปิดใช้งานการบีบอัดข้อมูลได้ การบีบอัดข้อมูลสามารถ (แต่จะไม่ "เสมอ") บีบอัดข้อมูล Unicode ในNCHARและNVARCHARฟิลด์ ปัจจัยที่กำหนดคือ:

    1. NCHAR(1 - 4000)และNVARCHAR(1 - 4000)ใช้Standard Compression Scheme สำหรับ Unicodeแต่จะเริ่มใน SQL Server 2008 R2 เท่านั้นและเฉพาะสำหรับข้อมูล ROW ไม่ใช่ OVERFLOW! สิ่งนี้ดูเหมือนจะดีกว่าอัลกอริทึมการบีบอัด ROW / PAGE ปกติ
    2. NVARCHAR(MAX)และXML(และฉันเดาด้วยVARBINARY(MAX) , TEXTและNTEXT) ข้อมูลที่มีอยู่ในแถว (ไม่ได้ปิดแถวในลอบหรือล้นหน้า) อย่างน้อยสามารถบีบอัดหน้า แต่ไม่แถวบีบอัด แน่นอนการบีบอัด PAGE ขึ้นอยู่กับขนาดของค่าในแถว: ฉันทดสอบด้วย VARCHAR (MAX) และเห็นว่าแถว 6000 ตัวอักษร / ไบต์จะไม่บีบอัด แต่แถว 4000 ตัวอักษร / ไบต์ไม่ได้
    3. ข้อมูล ROW ใด ๆ LOB หรือ OVERLOW = ไม่มีการบีบอัดข้อมูลสำหรับคุณ!
  2. ถ้าใช้ SQL Server 2005 หรือ 2008-2016 RTM และไม่เกี่ยวกับ Enterprise Edition คุณสามารถมีสองช่องหนึ่งและเป็นหนึ่งในVARCHAR NVARCHARตัวอย่างเช่นสมมติว่าคุณกำลังจัดเก็บ URL ซึ่งส่วนใหญ่เป็นอักขระ ASCII พื้นฐานทั้งหมด (ค่า 0 - 127) และอาจเหมาะสมVARCHARแต่บางครั้งก็มีอักขระ Unicode สคีมาของคุณสามารถมี 3 ฟิลด์ต่อไปนี้:

      ...
      URLa VARCHAR(2048) NULL,
      URLu NVARCHAR(2048) NULL,
      URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
      CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
                        ([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
                    AND ([URLa] IS NULL OR [URLu] IS NULL))
    );

    ในรุ่นนี้คุณเลือกเฉพาะจาก[URL]คอลัมน์ที่คำนวณ สำหรับการแทรกและอัปเดตคุณจะต้องกำหนดว่าจะใช้ฟิลด์ใดโดยดูว่าการแปลงเปลี่ยนค่าที่เข้ามาซึ่งต้องเป็นNVARCHARประเภทใด:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
  3. คุณสามารถ GZIP ค่าที่เข้ามาVARBINARY(MAX)แล้วเปิดเครื่องรูดที่ทางออก:

    • สำหรับ SQL Server 2005 - 2014: คุณสามารถใช้ SQLCLR SQL # (ไลบรารี SQLCLR ที่ฉันเขียน) มาพร้อมกับUtil_GZipและ Util_GUnzipในรุ่นฟรี
    • สำหรับ SQL Server 2016 และใหม่กว่า: คุณสามารถใช้ฟังก์ชันในตัวCOMPRESSและDECOMPRESSฟังก์ชันซึ่งก็คือ GZip
  4. หากใช้ SQL Server 2017 หรือใหม่กว่าคุณสามารถสร้างตารางเป็นดัชนีคอลัมน์แบบกลุ่มได้

  5. แม้ว่านี่จะไม่ใช่ตัวเลือกที่ทำงานได้ แต่ SQL Server 2019 แนะนำการสนับสนุนดั้งเดิมสำหรับ UTF-8 in VARCHAR/ CHARdatatypes ขณะนี้มีข้อบกพร่องมากเกินไปสำหรับมันที่จะใช้ แต่ถ้าพวกเขาได้รับการแก้ไขแล้วนี่คือตัวเลือกสำหรับบางสถานการณ์ โปรดดูโพสต์ของฉัน " Native UTF-8 รองรับใน SQL Server 2019: Savior หรือ False Prophet? " สำหรับการวิเคราะห์โดยละเอียดเกี่ยวกับคุณสมบัติใหม่นี้


7
ตบมือช้า ประหลาดใจเพียงแค่ว่า "ใช้ nvarchar เสมอ" ได้ 140 คะแนนและสิ่งนี้ไม่ได้ ใช้งานได้ดีกับโพสต์นี้
schizoid04

1
@ schizoid04 ขอบคุณ เพื่อความเป็นธรรมคำตอบที่ได้รับการยอมรับนั้นโพสต์เมื่อ 7 ปีก่อนของฉันดังนั้นจึงมีการรับส่งข้อมูลจำนวนมากที่โหวตให้กับมัน (และ / หรืออื่น ๆ อีกมากมาย) ที่ไม่เคยกลับมาประเมินอีกเลย ถึงกระนั้นก็ยังมีความแตกต่างที่แข็งแกร่งมากกับทฤษฎี "ภูมิปัญญาของฝูงชน" ที่ผลักดันฟอรั่มตามคะแนน มีข้อมูลที่ผิดมากเกินไป ตัวอย่างเช่นสิ่งนี้ใน DBA.SE คำตอบอื่น ๆ ที่ยอมรับก่อนที่ฉันจะโพสต์ของฉันคือ "ถูกต้อง" โดยคำจำกัดความที่แคบทำให้เข้าใจผิดและมีข้อมูลที่ฉันพิสูจน์หักล้างในของฉัน แต่มันก็ยังแซงหน้าฉัน
โซโลมอน Rutzky

22

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

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


10

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


8

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


7

ในช่วงไม่กี่ปีที่ผ่านมาทุกโครงการของเราใช้ NVARCHAR สำหรับทุกสิ่งเนื่องจากโครงการเหล่านี้เป็นแบบหลายภาษา ข้อมูลที่นำเข้าจากแหล่งภายนอก (เช่นไฟล์ ASCII เป็นต้น) จะถูกแปลงเป็น Unicode ก่อนที่จะถูกแทรกลงในฐานข้อมูล

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

ไม่ว่าคุณจะใช้โพรซีเดอร์ที่เก็บไว้หรือสร้าง SQL แบบทันทีให้แน่ใจว่าค่าคงที่สตริงทั้งหมดจะนำหน้าด้วย N (เช่น SET @foo = N'Hello world. ';) ดังนั้นค่าคงที่ก็เป็น Unicode วิธีนี้จะหลีกเลี่ยงการแปลงชนิดสตริงที่รันไทม์

YMMV


4
คุณอาจไม่มีหลายร้อยล้านบันทึกในตารางที่คุณทำงานด้วย ฉันยอมรับว่าสำหรับแอปส่วนใหญ่ที่เริ่มต้นกับ nvarchar นั้นใช้ได้ แต่ไม่ใช่ทั้งหมด
Brandon Moore

7

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


4

ฉันจัดการกับคำถามนี้ในที่ทำงานบ่อย ๆ :

  • ฟีด FTP ของสินค้าคงคลังและราคา - คำอธิบายรายการและข้อความอื่น ๆ อยู่ใน nvarchar เมื่อ varchar ทำงานได้ดี การแปลงไฟล์เหล่านี้เป็น varchar ลดขนาดไฟล์ลงเกือบครึ่งและช่วยให้มีการอัปโหลดได้อย่างแท้จริง

  • สถานการณ์ด้านบนทำงานได้ดีจนกระทั่งมีคนใส่อักขระพิเศษในคำอธิบายรายการ (อาจเป็นเครื่องหมายการค้าไม่สามารถจำได้)

ฉันยังไม่ได้ใช้ nvarchar ทุกครั้งที่ใช้ varchar หากมีข้อสงสัยหรือเป็นไปได้สำหรับตัวละครพิเศษฉันใช้ nvarchar ฉันพบว่าฉันใช้ varchar เป็นส่วนใหญ่เมื่อฉันอยู่ในการควบคุม 100% ของสิ่งที่กำลังเติมฟิลด์


3

ทำไมในการสนทนาทั้งหมดจึงไม่มีการพูดถึง UTF-8? ความสามารถในการเก็บช่วงอักขระ unicode ทั้งหมดไม่ได้หมายความว่าจะต้องจัดสรรสองไบต์ต่ออักขระ (หรือ "จุดรหัส" เสมอเพื่อใช้คำ UNICODE) ASCII ทั้งหมดคือ UTF-8 SQL Server ตรวจสอบฟิลด์ VARCHAR () ที่ข้อความนั้นเป็น ASCII ที่เข้มงวดหรือไม่ ฉันหวังว่าจะไม่

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

สำหรับคนที่ไม่คุ้นเคยกับ UTF-8 ฉันขอแนะนำไพรเมอร์ได้ไหม


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

1
ไม่สามารถจัดเก็บ UTF-8 ในคอลัมน์ VARCHAR MSSQL จะเสมอแปลงข้อมูล UTF-8 ของคุณเพื่อเปรียบเทียบคอลัมน์ หากคุณทำให้เกิดการเรียง (เช่นพยายามเก็บ CP1252 ใน Latin_1) การแปลงจะไม่ทำงานและคุณจะได้รับไบต์พิเศษในข้อมูลของคุณ มันอาจปรากฏในการทำงานที่ดีเมื่อคุณแปลง latin_1 ให้เป็น UTF-8 (ในด้านแอพพลิเค) และกลับมาอีกครั้งเพื่อ latin_1 (ด้าน dB) แต่มันเป็นเพียงภาพลวงตา คุณสามารถแอบดูโดยอัตโนมัติ DB แปลงเป็นคอลัมน์ของคุณโดยใช้ freetds และการตั้งค่าโปรโตคอลเป็นสิ่งที่น้อยกว่า 7 แต่คุณสูญเสียความสามารถในการสอบถาม nvarchar
chugadie

1
@chugadie และ Tevya: คำตอบนี้เป็นบิตที่ไม่ไร้สาระ SQL Server ใช้ UCS-2 / UTF-16 เท่านั้นในการจัดเก็บข้อมูล Unicode (เช่นชนิด XML และN-prefixed) คุณไม่ได้รับตัวเลือกในการใช้ UTF-8 นอกจากนี้ไม่สามารถใช้การเข้ารหัส Unicode (UTF-8, UCS-2 / UTF-16 และ UTF-32) กับเขตข้อมูล VARCHAR
โซโลมอน Rutzky

2

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


1

หากคุณกำลังใช้NVARCHARเพียงเพราะระบบจัดเก็บขั้นตอนที่ต้องใช้มันเกิดขึ้นบ่อยที่สุดลึกลับsp_executesqlและ SQL แบบไดนามิกของคุณยาวมากคุณจะดีขึ้นจากมุมมองประสิทธิภาพการทำงานของการจัดการสตริงทั้งหมด (concatenation แทน ฯลฯ ) ในVARCHARการแปลง ผลลัพธ์ที่ได้NVARCHARและการให้อาหารมันเป็นพารามิเตอร์ proc ดังนั้นไม่ใช้เสมอNVARCHAR!

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