Khi `nvarchar / nchar` sẽ được sử dụng với SQL Server 2019?


11

Với SQL Server 2019 Microsoft giới thiệu hỗ trợ UTF-8 cho CHARVARCHARkiểu dữ liệu và nói:

Tính năng này có thể cung cấp tiết kiệm lưu trữ đáng kể, tùy thuộc vào bộ ký tự được sử dụng. Ví dụ: thay đổi loại dữ liệu cột hiện có bằng chuỗi ASCII từ NCHAR (10) sang CHAR (10) bằng cách sử dụng đối chiếu được bật UTF-8, chuyển thành giảm gần 50% yêu cầu lưu trữ. Việc giảm này là do NCHAR (10) yêu cầu 22 byte để lưu trữ, trong khi CHAR (10) yêu cầu 12 byte cho cùng một chuỗi Unicode.

UTF-8 dường như hỗ trợ mọi tập lệnh, vì vậy về cơ bản chúng ta có thể bắt đầu lưu trữ dữ liệu Unicode trong varcharcharcột. Và như đã nói trong tài liệu này, điều này có thể làm giảm kích thước của các bảng và chỉ mục, và từ đó chúng ta có thể có được hiệu suất thậm chí tốt hơn, bởi vì lượng dữ liệu nhỏ hơn được đọc.

Tôi tự hỏi điều này có nghĩa là chúng ta có thể dừng sử dụng nvarcharncharcác cột thực hiện UTF-16?

Bất cứ ai cũng có thể chỉ ra một kịch bản và lý do, không sử dụng các kiểu dữ liệu char với UTFmã hóa và tiếp tục sử dụng các kiểu chữ n?


Tại sao bạn không kiểm tra nó và báo cáo lại? Đồng thời cho chúng tôi biết bạn đã dành bao nhiêu nỗ lực để chuyển đổi từ nvarchar sang varchar - các bảng thay đổi mất bao lâu và thời gian bạn đã thử nghiệm và những vấn đề bạn gặp phải.
Colin 't Hart

@ Colin'tHart Nếu không có bất kỳ vấn đề hoặc cân nhắc nào tôi biết tôi dự định di chuyển dữ liệu vì tôi tin rằng việc đọc ít dữ liệu sẽ dẫn đến hiệu suất tốt hơn cho hệ thống. Về việc chuyển đổi - tất nhiên sẽ mất thời gian, đặc biệt nếu bạn có các chỉ mục với cột đã cho - chúng cần được xây dựng lại, nhưng tôi tin rằng nó sẽ được đền đáp xứng đáng. Tất nhiên tôi sẽ sớm kiểm tra tác động hiệu suất, chỉ cần tìm kiếm bất kỳ vấn đề nào sẽ khiến việc di chuyển không cần thiết.
gotqn

Lưu ý rằng SQL Server hỗ trợ nén Unicode cho các cột NVarchar khi sử dụng nén PAGE hoặc ROW. docs.microsoft.com/en-us/sql/relational-database/ từ
David Browne - Microsoft

1
Điều đáng chú ý là mặc dù UTF-8 có thể tiết kiệm dung lượng nếu bạn đang lưu trữ "dữ liệu giống ASCII", nhưng nó không tự nén và không nên nhầm lẫn như vậy. Ví dụ: nếu bạn lưu trữ chủ yếu tên tiếng Trung trong cơ sở dữ liệu, bạn sẽ sử dụng các loại UTF-8 tệ hơn các CHARloại Unicode (có hoặc không nén, vì cuối cùng dữ liệu cần phải được giải nén). Cũng xem xét rằng loại chuỗi gốc của Windows là Unicode, do đó, chuỗi UTF-8 thường cần được giải mã. Sự đánh đổi liên quan có nghĩa là không có khả năng các Nloại sẽ bị loại bỏ bất cứ lúc nào sớm.
Jeroen Mostert

1
"Ứng dụng sát thủ" số 1 cho UTF-8 CHARcó lẽ là SQL Server trên Linux, nếu công cụ nhận được hỗ trợ riêng để xử lý chuỗi trực tiếp dưới dạng UTF-8 - ở đây UTF-8 là bộ ký tự "gốc" (ít nhiều) và giữ các chuỗi xung quanh vì UTF-16 là sự thay thế kém hiệu quả hơn. Dĩ nhiên, sẽ không hại khi sử dụng nó trên Windows ở những nơi bạn đang sử dụng CHAR, vì các bộ sưu tập hạn chế các ký tự có thể được lưu trữ chưa bao giờ hấp dẫn.
Jeroen Mostert

Câu trả lời:


6

điều này có thể làm giảm kích thước của bảng và chỉ mục (nhấn mạnh thêm)

Giảm kích thước duy nhất là có thể nếu hầu hết các nhân vật chủ yếu [space], 0 - 9, A - Z, a - z, và một số dấu câu cơ bản. Bên ngoài đó tập hợp cụ thể của nhân vật (trong điều kiện sử dụng thực tế, giá trị ASCII chuẩn 32-126), bạn sẽ có ít nhất tương đương với kích thước đến NVARCHAR/ UTF-16, hoặc trong nhiều trường hợp lớn hơn.

Tôi đang lên kế hoạch di chuyển dữ liệu vì tôi tin rằng việc đọc ít dữ liệu sẽ dẫn đến hiệu suất tốt hơn cho hệ thống.

Hãy cẩn thận. UTF-8 không phải là một công tắc "sửa chữa mọi thứ" kỳ diệu. Tất cả những thứ khác đều bình đẳng, vâng, đọc ít hơn sẽ cải thiện hiệu suất. Nhưng ở đây "tất cả những thứ khác" không bằng nhau. Ngay cả khi chỉ lưu trữ các ký tự ASCII tiêu chuẩn (có nghĩa là: tất cả các ký tự là 1 byte, do đó cần một nửa dung lượng so với lưu trữ NVARCHAR), vẫn có một hiệu suất phạt nhẹ khi sử dụng UTF-8. Tôi tin rằng vấn đề là do UTF-8 là một mã hóa có độ dài thay đổi, có nghĩa là mỗi byte phải được hiểu khi nó được đọc để biết liệu đó có phải là một ký tự hoàn chỉnh hay nếu byte tiếp theo là một phần của nó. Điều này có nghĩa là tất cả các hoạt động chuỗi cần bắt đầu từ đầu và tiến hành từng byte một. Mặt khác,NVARCHAR / UTF-16 luôn là 2 byte (ngay cả các ký tự bổ sung cũng bao gồm hai Điểm mã 2 byte), vì vậy mọi thứ có thể được đọc trong các đoạn 2 byte.

Trong thử nghiệm của tôi, ngay cả khi chỉ có các ký tự ASCII tiêu chuẩn, việc lưu trữ dữ liệu dưới dạng UTF-8 không giúp tiết kiệm thời gian trôi qua, nhưng chắc chắn là tồi tệ hơn đối với thời gian của CPU. Và đó là không có nén dữ liệu, nên ít nhất có ít không gian đĩa được sử dụng. Nhưng, khi sử dụng nén, không gian cần thiết cho UTF-8 chỉ nhỏ hơn 1% - 1,5%. Vì vậy, hiệu quả không tiết kiệm không gian nhưng thời gian CPU cao hơn cho UTF-8.

Mọi thứ trở nên phức tạp hơn khi sử dụng NVARCHAR(MAX)vì Unicode Nén không hoạt động với kiểu dữ liệu đó, ngay cả khi giá trị đủ nhỏ để được lưu trữ liên tiếp. Nhưng, nếu dữ liệu đủ nhỏ, nó vẫn sẽ được hưởng lợi từ Nén hàng hoặc nén trang (trong trường hợp đó nó thực sự trở nên nhanh hơn UTF-8). Tuy nhiên, dữ liệu ngoài hàng không thể sử dụng bất kỳ nén. Tuy nhiên, làm cho bảng trở thành một Chỉ số kho lưu trữ theo cụm giúp giảm đáng kể kích thước NVARCHAR(MAX)(ngay cả khi nó vẫn lớn hơn một chút so với UTF-8 khi sử dụng Chỉ mục kho lưu trữ theo cụm).

Bất cứ ai cũng có thể chỉ ra một kịch bản và lý do, không sử dụng các kiểu dữ liệu char với mã hóa UTF

Chắc chắn rồi. Trên thực tế, tôi không thực sự tìm thấy một lý do thuyết phục để sử dụng nó trong hầu hết các trường hợp. Kịch bản duy nhất thực sự được hưởng lợi từ UTF-8 là:

  1. Dữ liệu chủ yếu là tiêu chuẩn ASCII (giá trị 0 - 127)
  2. Nó cần phải là Unicode vì có thể cần lưu trữ một phạm vi ký tự rộng hơn mức có sẵn trên bất kỳ Trang mã 8 bit nào (nghĩa là VARCHAR)
  3. Hầu hết dữ liệu được lưu trữ ngoài hàng (do đó, nén trang thậm chí không hoạt động)
  4. Bạn có đủ dữ liệu mà bạn cần / muốn giảm kích thước vì lý do hiệu năng không truy vấn (ví dụ: giảm kích thước sao lưu, giảm thời gian cần thiết để sao lưu / khôi phục, v.v.)
  5. Bạn không thể sử dụng Indexed Clusterstore Index (có lẽ việc sử dụng bảng làm cho hiệu suất kém hơn trong trường hợp này?)

Thử nghiệm của tôi cho thấy rằng trong hầu hết các trường hợp, NVARCHAR đã nhanh hơn, đặc biệt là khi có nhiều dữ liệu hơn. Trên thực tế, 21k hàng với trung bình 5k ký tự mỗi hàng cần 165 MB cho UTF-8 và 236 MB cho NVARCHARkhông nén. Tuy nhiên NVARCHAR, thời gian trôi nhanh hơn gấp 2 lần và nhanh hơn ít nhất gấp 2 lần (đôi khi nhiều hơn) trong thời gian CPU. Tuy nhiên, nó đã chiếm thêm 71 MB trên đĩa.

Ngoài ra, tôi vẫn không khuyến nghị sử dụng UTF-8, ít nhất là với CTP 2, do một loạt các lỗi mà tôi đã tìm thấy trong tính năng này.

Để biết phân tích chi tiết về tính năng mới này, bao gồm giải thích về sự khác biệt giữa UTF-16 và UTF-8 và danh sách các lỗi đó, vui lòng xem bài đăng của tôi:

Hỗ trợ UTF-8 bản địa trong SQL Server 2019: Tiên tri cứu rỗi hay sai?


12

Hỗ trợ UTF-8 cung cấp cho bạn một bộ tùy chọn mới. Tiết kiệm không gian tiềm năng (không nén hàng hoặc nén trang ) là một điều cần cân nhắc, nhưng việc lựa chọn loại và mã hóa có lẽ nên được thực hiện chủ yếu dựa trên các yêu cầu thực tế để so sánh, sắp xếp, nhập dữ liệu và xuất .

Bạn có thể cần thay đổi nhiều hơn bạn nghĩ, ví dụ như một nchar(1)loại cung cấp hai byte lưu trữ. Chừng đó là đủ để lưu trữ bất kỳ ký tự nào trong BMP (mã điểm 000000 đến 00FFFF). Một số ký tự trong phạm vi đó sẽ được mã hóa chỉ với 1 byte trong UTF-8 trong khi các ký tự khác sẽ yêu cầu 2 hoặc thậm chí 3 byte (xem biểu đồ so sánh này để biết thêm chi tiết). Do đó, đảm bảo phạm vi bảo hiểm của cùng một bộ ký tự trong UTF-8 sẽ yêu cầu char(3).

Ví dụ:

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);

đưa ra lỗi quen thuộc:

Msg 8152, Cấp 16, Trạng thái 30,
Chuỗi xxx hoặc dữ liệu nhị phân sẽ bị cắt ngắn.

Hoặc nếu cờ theo dõi 460 đang hoạt động:

Msg 2628, Cấp 16, Trạng thái 1,
Chuỗi xxx hoặc dữ liệu nhị phân sẽ bị cắt ngắn trong bảng '@T', cột 'UTF8'. Giá trị rút gọn: ''.

Mở rộng cột UTF8 thành char(2)hoặc varchar(2)giải quyết lỗi cho 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);

Tuy nhiên, nếu đó là ví dụ NCHAR(8364), bạn sẽ cần mở rộng cột hơn nữa, thành char(3)hoặc varchar(3).

Cũng lưu ý rằng tất cả các bộ sưu tập UTF-8 đều sử dụng các ký tự bổ sung, do đó sẽ không hoạt động với sao chép.

Ngoài bất cứ điều gì khác, hỗ trợ UTF-8 chỉ được xem trước tại thời điểm này, vì vậy không có sẵn cho sử dụng sản xuất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.