got*_*tqn 12 sql-server datatypes utf-8 unicode sql-server-2019
在 SQL Server 2019 中,Microsoft 引入了对和数据类型的UTF-8 支持,并表示:CHARVARCHAR
此功能可显着节省存储空间,具体取决于使用的字符集。例如,使用支持 UTF-8 的归类将带有 ASCII 字符串的现有列数据类型从 NCHAR(10) 更改为 CHAR(10),意味着存储需求减少了近 50%。这种减少是因为 NCHAR(10) 需要 22 个字节的存储空间,而 CHAR(10) 需要 12 个字节来存储相同的 Unicode 字符串。
UTF-8似乎支持每个脚本,所以基本上我们就可以开始在存储Unicode数据varchar和char列。正如文档中所说,这可以减少表和索引的大小,从那里我们可以获得更好的性能,因为读取的数据量更少。
我想知道这是不是意味着我们可以停止使用nvarchar和nchar列,它实现UTF-16?
任何人都可以指出一个场景和原因,不要使用带有UTF编码的 char 数据类型并继续使用 n-chars数据类型吗?
Pau*_*ite 13
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);
Run Code Online (Sandbox Code Playgroud)
给出了熟悉的错误:
消息 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);
Run Code Online (Sandbox Code Playgroud)
但是,如果它是 eg NCHAR(8364),则您需要进一步扩展该列到char(3)或varchar(3)。
另请注意,UTF-8 排序规则都使用补充字符,因此不适用于复制。
除此之外,UTF-8 支持目前仅处于预览阶段,因此无法用于生产用途。
这可以减少表和索引的大小(强调添加)
减少大小只可能是,大部分的人物基本上[space],0 - 9,A - Z,a - z,和一些基本的标点符号。在该特定字符集之外(在实际使用术语中,标准 ASCII 值 32 - 126),您的大小最多等于NVARCHAR/ UTF-16,或者在许多情况下更大。
我计划迁移数据,因为我相信读取更少的数据会导致系统的性能更好。
当心。UTF-8 不是一个神奇的“修复一切”开关。在所有其他条件相同的情况下,是的,减少阅读确实会提高性能。但在这里“所有其他事物”并不相等。即使只存储标准 ASCII 字符(意思是:所有字符都是 1 个字节,因此与存储在/ UTF-16 中相比需要一半的空间总是 2 个字节(即使补充字符由两个 2 字节代码点组成),所以一切都可以以 2 字节的块读取。NVARCHAR),使用 UTF-8 也有轻微的性能损失。我认为这个问题是由于 UTF-8 是一种可变长度编码,这意味着必须在读取每个字节时对其进行解释,才能知道它是一个完整的字符还是下一个字节是它的一部分。这意味着所有字符串操作都需要从头开始并逐字节进行。另一方面,NVARCHAR
在我的测试中,即使只有标准 ASCII 字符,将数据存储为 UTF-8 也不会节省时间,但 CPU 时间肯定更糟。那是没有数据压缩,所以至少使用的磁盘空间更少。但是,使用压缩时,UTF-8 所需的空间仅小 1% - 1.5%。因此,对于 UTF-8,实际上没有空间节省,但 CPU 时间更长。
使用时事情变得更加复杂,NVARCHAR(MAX)因为 Unicode 压缩不适用于该数据类型,即使该值小到足以存储在行中。但是,如果数据足够小,它仍然应该受益于行或页面压缩(在这种情况下,它实际上比 UTF-8 更快)。但是,行外数据不能使用任何压缩。尽管如此,使表成为聚集列存储索引确实大大减少了大小NVARCHAR(MAX)(即使在使用聚集列存储索引时它仍然比 UTF-8 略大)。
任何人都可以指出一个场景和原因,不要使用带有 UTF 编码的 char 数据类型
确实。事实上,在大多数情况下,我并没有真正找到使用它的令人信服的理由。唯一真正受益于 UTF-8 的场景是:
VARCHAR)我的测试表明,几乎在所有情况下,NVARCHAR 都更快,尤其是在有更多数据时。实际上,对于 UTF-8,平均每行5k 个字符的21k 行需要 165 MB,NVARCHAR未压缩需要 236 MB 。然而,NVARCHAR它的运行时间快了 2 倍,CPU 时间至少快了 2 倍(有时更多)。尽管如此,它确实多占用了 71 MB 的磁盘空间。
除此之外,我仍然不建议使用 UTF-8,至少从 CTP 2 开始,因为我在此功能中发现了各种错误。
有关此新功能的详细分析,包括对 UTF-16 和 UTF-8 之间差异的解释以及这些错误的列表,请参阅我的帖子:
SQL Server 2019 中的原生 UTF-8 支持:救世主还是假先知?