เมื่อจะใช้ 'nvarchar / nchar' กับ SQL Server 2019?


11

กับ SQL Server 2019 ไมโครซอฟท์เปิดตัวสนับสนุน UTF-8สำหรับCHARและVARCHARชนิดข้อมูลและพูดว่า:

คุณสมบัตินี้อาจช่วยประหยัดพื้นที่เก็บข้อมูลได้อย่างมากทั้งนี้ขึ้นอยู่กับชุดอักขระที่ใช้งาน ตัวอย่างเช่นการเปลี่ยนชนิดข้อมูลคอลัมน์ที่มีอยู่ด้วยสตริง ASCII จาก NCHAR (10) เป็น CHAR (10) โดยใช้การเปรียบเทียบการเปิดใช้งาน UTF-8 แปลเป็นความต้องการหน่วยเก็บข้อมูลลดลงเกือบ 50% การลดลงนี้เป็นเพราะ NCHAR (10) ต้องการ 22 ไบต์สำหรับการจัดเก็บในขณะที่ CHAR (10) ต้องการ 12 ไบต์สำหรับสายอักขระ Unicode เดียวกัน

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

ฉันสงสัยว่านี่หมายความว่าเราสามารถหยุดใช้nvarcharและncharคอลัมน์ที่ใช้ UTF-16 หรือไม่

ใครสามารถชี้สถานการณ์และเหตุผลที่จะไม่ใช้ชนิดข้อมูลถ่านด้วยการUTFเข้ารหัสและใช้ n-chars ต่อไปได้?


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

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

โปรดทราบว่า SQL Server รองรับการบีบอัด Unicode สำหรับคอลัมน์ NVarchar เมื่อใช้การบีบอัด PAGE หรือ ROW docs.microsoft.com/en-us/sql/relational-database/…
David Browne - Microsoft

1
เป็นที่น่าสังเกตว่าในขณะที่ UTF-8 อาจประหยัดพื้นที่หากคุณเก็บ "ข้อมูลที่เหมือน ASCII" แต่ก็ไม่ได้บีบอัดข้อมูลเข้าและออกเองและไม่ควรเข้าใจผิดเช่นนั้น ตัวอย่างเช่นถ้าคุณเก็บชื่อภาษาจีนเป็นหลักในฐานข้อมูลคุณจะแย่ลงโดยใช้ UTF-8 CHARชนิดกว่า Unicode ประเภท (มีหรือไม่มีการบีบอัดเนื่องจากในที่สุดข้อมูลจะต้องมีการบีบอัดเพื่อประมวลผล) พิจารณาว่าประเภทสตริงเนทิฟของ Windows คือ Unicode ดังนั้นจึงจำเป็นต้องถอดรหัสสตริง UTF-8 การแลกเปลี่ยนที่เกี่ยวข้องหมายความว่าไม่น่าจะมีการยกเลิกNประเภทในเวลาใด ๆ ในไม่ช้า
Jeroen Mostert

1
# 1 "killer App" สำหรับ UTF-8 CHARน่าจะเป็น SQL Server บน Linux ถ้าเอ็นจิ้นได้รับการสนับสนุนดั้งเดิมสำหรับการประมวลผลสตริงโดยตรงเป็น UTF-8 - ที่นี่ UTF-8 คือชุดอักขระ "เนทีฟ" (มากหรือน้อย) และการเก็บรักษาสตริงไว้เป็น UTF-16 เป็นทางเลือกที่มีประสิทธิภาพน้อยกว่า นอกจากนี้ยังไม่เจ็บที่จะใช้งานบน Windows ในสถานที่ที่คุณใช้อยู่แล้วCHARเนื่องจากการเรียงการ จำกัด อักขระที่สามารถจัดเก็บได้ไม่เคยมีเสน่ห์
Jeroen Mostert

คำตอบ:


6

สิ่งนี้สามารถลดขนาดของตารางและดัชนี (เน้นเพิ่ม)

การลดขนาดเป็นเพียงเป็นไปได้ถ้าส่วนใหญ่ของตัวละครเป็นหลัก[space], 0 - 9, A - Z, a - zและบางวรรคตอนพื้นฐาน นอกเหนือจากชุดอักขระเฉพาะนั้น (ในแง่การใช้งานจริง, ค่า ASCII มาตรฐาน 32 - 126), คุณจะมีขนาดเท่ากับ/ UTF-16 ที่ดีที่สุดNVARCHARหรือในหลายกรณีที่ใหญ่กว่า

ฉันวางแผนที่จะย้ายข้อมูลเนื่องจากฉันเชื่อว่าการอ่านข้อมูลน้อยลงจะนำไปสู่ประสิทธิภาพที่ดีขึ้นสำหรับระบบเลย

ระวัง. UTF-8 ไม่ใช่สวิตช์ "แก้ไขทุกอย่าง" ที่น่าอัศจรรย์ สิ่งอื่น ๆ ที่เท่าเทียมกันใช่การอ่านน้อยจะช่วยปรับปรุงประสิทธิภาพ แต่ที่นี่ "สิ่งอื่น ๆ ทั้งหมด" ไม่เท่ากัน แม้ว่าการจัดเก็บเฉพาะอักขระ ASCII มาตรฐาน (ความหมาย: อักขระทั้งหมดมี 1 ไบต์ดังนั้นจึงต้องใช้พื้นที่ครึ่งหนึ่งเมื่อเทียบกับการจัดเก็บในNVARCHAR) มีโทษประสิทธิภาพเล็กน้อยสำหรับการใช้ UTF-8 ฉันเชื่อว่าปัญหานี้เกิดจากการเข้ารหัส UTF-8 ซึ่งมีความยาวผันแปรได้ซึ่งหมายความว่าแต่ละไบต์จะต้องตีความตามที่อ่านเพื่อที่จะทราบว่าเป็นอักขระที่สมบูรณ์หรือถ้าไบต์ต่อไปเป็นส่วนหนึ่งของมัน ซึ่งหมายความว่าการดำเนินการสตริงทั้งหมดต้องเริ่มต้นที่จุดเริ่มต้นและดำเนินการไบต์ต่อไบต์ ในทางกลับกัน,NVARCHAR / UTF-16 มีขนาด 2 ไบต์เสมอ (แม้อักขระเสริมจะประกอบด้วยคะแนนรหัส 2 ไบต์) ดังนั้นทุกอย่างสามารถอ่านได้ในหน่วยย่อย 2 ไบต์

ในการทดสอบของฉันแม้จะมีเพียงอักขระ ASCII มาตรฐานเท่านั้นการจัดเก็บข้อมูลในรูปแบบ UTF-8 ก็ไม่ได้ช่วยประหยัดเวลา แต่ก็แย่กว่าสำหรับเวลาของ CPU และนั่นก็คือไม่มีการบีบอัดข้อมูลดังนั้นอย่างน้อยก็มีการใช้พื้นที่ดิสก์น้อยลง แต่เมื่อใช้การบีบอัดพื้นที่ที่ต้องการสำหรับ UTF-8 นั้นมีขนาดเล็กลงเพียง 1% - 1.5% ดังนั้นจึงไม่มีการประหยัดพื้นที่ แต่ให้เวลา CPU ที่สูงขึ้นสำหรับ UTF-8

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

ทุกคนสามารถชี้สถานการณ์และเหตุผลที่จะไม่ใช้ชนิดข้อมูลถ่านด้วยการเข้ารหัส UTF

อย่างแน่นอน. ที่จริงแล้วฉันไม่พบเหตุผลที่น่าสนใจที่จะใช้ในกรณีส่วนใหญ่ สถานการณ์เดียวที่ได้รับประโยชน์อย่างแท้จริงจาก UTF-8 คือ:

  1. ข้อมูลส่วนใหญ่เป็น ASCII มาตรฐาน (ค่า 0 - 127)
  2. ต้องเป็น Unicode เพราะอาจต้องเก็บอักขระที่กว้างกว่าที่มีในหน้ารหัส 8 บิต (เช่นVARCHAR)
  3. ข้อมูลส่วนใหญ่ถูกจัดเก็บแบบออฟไลน์ (ดังนั้นการบีบอัดหน้าจึงไม่ทำงาน)
  4. คุณมีข้อมูลเพียงพอที่คุณต้องการ / ต้องการลดขนาดด้วยเหตุผลที่ไม่ใช่แบบสอบถามประสิทธิภาพ (เช่นลดขนาดการสำรองข้อมูลลดเวลาที่ต้องใช้ในการสำรองข้อมูล / คืนค่า ฯลฯ )
  5. คุณไม่สามารถใช้ดัชนี Columnstore ที่เป็นกลุ่ม (บางทีการใช้ตารางทำให้ประสิทธิภาพแย่ลงในกรณีนี้ใช่ไหม)

การทดสอบของฉันแสดงให้เห็นว่าในเกือบทุกกรณี NVARCHAR นั้นเร็วกว่าโดยเฉพาะเมื่อมีข้อมูลมากขึ้น อันที่จริงแล้วแถว 21k ที่มีค่าเฉลี่ย 5k อักขระต่อแถวจำเป็นต้องมี 165 MB สำหรับ UTF-8 และ 236 MB สำหรับNVARCHARการยกเลิกการบีบอัด และยังNVARCHARเร็วกว่า 2x ในเวลาที่ผ่านไปและอย่างน้อย 2x เร็ว (บางครั้ง) ในเวลา CPU ถึงกระนั้นมันใช้เนื้อที่ดิสก์มากขึ้นถึง 71 MB

นอกเหนือจากนั้นฉันยังคงไม่แนะนำให้ใช้ UTF-8 อย่างน้อยเป็น CTP 2 เนื่องจากมีข้อบกพร่องหลายอย่างที่ฉันพบในคุณลักษณะนี้

สำหรับการวิเคราะห์โดยละเอียดของคุณสมบัติใหม่นี้รวมถึงคำอธิบายความแตกต่างระหว่าง UTF-16 และ UTF-8 และรายชื่อของข้อบกพร่องเหล่านั้นโปรดดูโพสต์ของฉัน:

สนับสนุน UTF-8 ดั้งเดิมใน SQL Server 2019: Savior หรือ False Prophet?


12

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

คุณอาจจำเป็นต้องเปลี่ยนแปลงมากกว่าที่คุณคิดเนื่องจากเช่นnchar(1)ประเภทให้พื้นที่เก็บข้อมูลสองไบต์ นั่นก็เพียงพอที่จะเก็บอักขระใด ๆ ในBMP (รหัสคะแนน 000000 ถึง 00FFFF) อักขระบางตัวในช่วงนั้นจะถูกเข้ารหัสด้วยเพียง 1 ไบต์ใน UTF-8 ในขณะที่คนอื่น ๆ จะต้องมี 2 หรือ 3 ไบต์ (ดูแผนภูมิเปรียบเทียบนี้เพื่อดูรายละเอียดเพิ่มเติม) ดังนั้นจึงมั่นใจได้ว่าการรายงานข่าวของชุดเดียวกันของตัวละครใน UTF-8 char(3)จะต้อง

ตัวอย่างเช่น:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

ให้ข้อผิดพลาดที่คุ้นเคย:

ข่าวสารเกี่ยวกับ 8152 ระดับ 16 สถานะ 30
สตริงxxx สตริงหรือข้อมูลไบนารีจะถูกตัดทอน

หรือถ้าการติดตามสถานะ 460 ใช้งานอยู่:

ข่าวสารเกี่ยวกับ 2628 ระดับ 16 สถานะ 1
สตริงxxx สตริงหรือข้อมูลไบนารีจะถูกตัดทอนในตาราง '@T' คอลัมน์ 'UTF8' ค่าที่ตัดปลาย: ''

การขยายคอลัมน์ UTF8 เป็นchar(2)หรือvarchar(2)แก้ไขข้อผิดพลาดสำหรับNCHAR(911):

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

แต่ถ้ามันเป็นเช่นNCHAR(8364)นี้คุณจะต้องขยายคอลัมน์ต่อไปหรือchar(3)varchar(3)

โปรดทราบว่าการเปรียบเทียบ UTF-8 ทั้งหมดใช้อักขระเสริมดังนั้นจะไม่ทำงานกับการจำลองแบบ

นอกเหนือจากสิ่งอื่นการรองรับ UTF-8 เป็นเพียงการแสดงตัวอย่างในเวลานี้เท่านั้นดังนั้นจึงไม่สามารถใช้งานได้จริง

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