什么时候必须在 SQLServer 中使用 NVARCHAR/NCHAR 而不是 VARCHAR/CHAR?

当我们必须使用 Unicode 类型时,是否有一个规则?

我看到大多数欧洲语言(德语、意大利语、英语,...)在 VARCHAR 列的同一数据库中都很好。

我在寻找这样的东西:

  1. 如果你有中文-> 使用 NVARCHAR
  2. 如果你有德语和阿拉伯语-> 使用 NVARCHAR

服务器/数据库的排序规则如何?

我不想像这里建议的那样总是使用 NVARCHAR Varchar 和 nvarchar SQLServer 数据类型之间的主要性能差异是什么?

126291 次浏览

希腊语在 N 列类型上需要 UTF-8: αβγ;)

在必须存储多种语言的任何时候,都应该使用 NVARCHAR。我相信你必须使用它的亚洲语言,但不要引用我对它。

以俄语为例,如果将它存储在 varchar 中,那么问题就出现了,只要定义了正确的代码页就可以了。但是,假设您使用默认的英语 sql 安装,那么将无法正确处理俄语字符。如果您使用的是 NVARCHAR () ,那么它们将得到正确的处理。

剪辑

好吧,让我引用 MSDN,也许我是具体的,但你不想存储多于一个代码页在一个 varcar 列,而你可以,你不应该

当您处理文本数据时, 存储在 char,varchar 中, Varchar (max)或文本数据类型,则 最重要的限制 只有来自一个 代码页可以通过 系统。(你可以从 多个代码页,但这不是 )所使用的确切代码页 验证和存储数据取决于 列的排序规则。如果 列级排序规则 定义了数据库的排序规则 用于确定代码页 用于给定列的 可以使用 COLLATIONProperty 函数,如下所示 代码示例:

这里还有一些:

这个例子说明了这样一个事实 许多地方,如格鲁吉亚和 印地语,没有代码页,因为他们 是仅 Unicode 排序规则 排序法不适用于 使用 char、 varchar 或 文本数据类型

因此,格鲁吉亚语或印地语确实需要以 nvarchar 的形式存储。阿拉伯语也是一个问题:

您可能会遇到的另一个问题是 不能存储数据时 所有你想要的角色 支持包含在代码中 在许多情况下,Windows 会考虑 一个特定的代码页是一个“最好的 “适合”代码页,这意味着存在 不能保证你可以依赖 处理所有文本的代码页; 它是 仅仅是最好的一个可用的。一个 这方面的例子是阿拉伯文字: 它支持多种语言, 包括俾路支,柏柏尔,波斯语, 克什米尔,哈萨克,吉尔吉斯,Pashto 信德语,维吾尔语,乌尔都语,等等 这些语言有额外的 阿拉伯语以外的文字 在 Windows 代码中定义的语言 第1256页。如果您试图存储 中的这些额外字符 具有阿拉伯语 排序,字符是 变成了问号。

在使用 Unicode 时需要记住的一点是,尽管可以在单列中存储不同的语言,但只能使用单个排序规则进行排序。有些语言使用拉丁字符,但与其他拉丁语言不同。口音就是一个很好的例子,我不记得这个例子了,但是有一种东欧语言的 Y 和英语的 Y 不一样。然后是西班牙语,西班牙语用户希望在 h 之后进行排序。

总而言之,在处理国际化问题时,你必须处理所有的问题。我的观点是,从一开始就使用 Unicode 字符更容易,避免额外的转换,并承受空间冲击。这就是我之前的陈述。

你想使用 NVARCHAR 的真正原因是当你在同一列中使用 与众不同语言时,你需要在不解码的情况下在 T-SQL 中寻址这些列,你想能够在 SSMS 中“原生”地看到数据,或者你想在 Unicode 上标准化。

如果将数据库视为非智能存储,则完全可以在 VARCHAR (例如 UTF-8)中存储宽字符串和不同(甚至可变长度)编码。当您试图编码和解码时,特别是当代码页对于不同的行是不同的时候,问题就会出现。这还意味着 SQLServer 将无法轻松处理用于在 T-SQL 中查询(可能是可变的)编码列的数据。

使用 NVARCHAR 可以避免这一切。

我建议 NVARCHAR 用于任何列,这些列中将包含用户输入的数据,而这些数据是相对不受限制的。

我会推荐 VARCHAR 作为一个自然键(比如车牌号、 SSN、序列号、服务标签、订单号、机场呼号等等)的列,它通常是由标准、立法或惯例定义和约束的。还有 VARCHAR,用于用户输入的、非常受限制的(比如电话号码)或代码(AActive/CLOSED、 Y/N、 M/F、 M/S/D/W 等)。绝对没有理由为这些使用 NVARCHAR。

因此,对于一个简单的规则:

保证受约束的 VARCHAR 否则 NVARCHAR

乔什表示: ”... ... 在使用 Unicode 时需要记住的一点是,尽管可以将不同的语言存储在单个列中,但只能使用单个排序规则进行排序。有些语言使用拉丁字符,但与其他拉丁语言不同。口音就是一个很好的例子,我不记得这个例子了,但是有一种东欧语言的 Y 和英语的 Y 不一样。还有西班牙语,西班牙用户希望在 h 之后进行排序。”

我的母语是西班牙语,“ ch”不是一个字母,而是两个“ c”和“ h”,西班牙语字母是这样的: (咒语) 我们不期望“ ch”在“ h”之后,但是“ i” 除了 ñ 或 HTML“ & ntilde;”中的字母表与英语中的字母表相同之外,其他字母表都与英语中的字母表相同

亚历克斯

;
Unicode-(nchar、 nvarchar 和 ntext)
非 unicode-(char、 varchar 和 text)。

来自 MSDN

SQLServer 中的排序规则提供排序规则、大小写和重音 数据的敏感性属性。与 诸如 char 和 varchar 之类的字符数据类型指示代码页 和对应的字符,可以表示该数据 类型。

假设你使用默认的 SQL 排序法 SQL_Latin1_General_CP1_CI_AS,那么下面的脚本应该打印出所有符号,你可以适合在 VARCHAR,因为它使用一个字节来存储一个字符(总共256个) ,如果你没有看到它在列表上打印-你需要 NVARCHAR

declare @i int = 0;
while (@i < 256)
begin
print cast(@i as varchar(3)) + '  '+  char(@i)  collate SQL_Latin1_General_CP1_CI_AS
print cast(@i as varchar(3)) + '  '+ char(@i)  collate Japanese_90_CI_AS
set @i = @i+1;
end

如果你改变排序,让说日语,你会注意到,所有的奇怪的欧洲字母变成正常的,一些符号成为 ?标记。

Unicode 是将代码点映射到字符的标准 它的目的是涵盖所有的语言的所有字符 世界上,不需要不同的代码页来处理不同的 如果存储的字符数据反映多个 语言,始终使用 Unicode 数据类型(nchar、 nvarchar 和 ntext) 而不是非 Unicode 数据类型(char、 varchar 和 text)。

否则你的分类会变得很奇怪。

如果有人在 Mysql 中遇到这个问题,不需要将 varchar 更改为 nvarchar,只需将列的排序规则更改为 utf8即可

两个最受欢迎的答案都是错误的。它应该与“存储不同/多种语言”无关。您可以支持西班牙文字符,如 ñ和英语,只有通用的 varchar字段和 Latin1_General_CI_AS COLLATION,例如。

简而言之
只要 ENCODING(由字段的 COLLATION确定)不支持所需的字符,就应该使用 NVARCHAR/NCHAR
此外,根据 SQLServer 版本的不同,您可以使用特定的 COLLATIONs,比如自 SQLServer2019以来就可以使用的 Latin1_General_100_CI_AS_SC_UTF8。将此排序规则设置为 VARCHAR字段(或整个表/数据库) ,将使用 UTF-8 ENCODING来存储和处理该字段上的数据,从而允许完全支持 UNICODE字符,以及它所包含的任何语言。


要充分理解:
为了完全理解我将要解释的内容,你必须非常清楚地记住 UNICODEENCODINGCOLLATION的概念。如果你没有,那么首先看看下面我简单的解释“什么是联合编码,编码,排序和 UTF-8,以及它们是如何相关的”部分和提供的文档链接。此外,我在这里所说的一切都是特定于 Microsoft SQL Server的,以及它如何在 char/ncharvarchar/nvarchar字段中存储和处理数据。

Let's say we wanna store a peculiar text on our MSSQL Server database. It could be an Instagram comment as "I love stackoverflow! 😍".
即使是 ASCII 也完全支持简单的英语部分,但是由于还有一个表情符号,这是一个在 UNICODE标准中指定的字符,我们需要一个支持这个 Unicode字符的 ENCODING。< br/>

MSSQL Server 使用 COLLATION来确定在 char/nchar/varchar/nvarchar字段中使用哪些 ENCODING。因此,不同于很多人的想法,COLLATION 不是只是关于排序和比较数据,但也关于 ENCODING,并由结果: 我们的数据将如何存储!

那么 我们如何知道排序所使用的编码?是这样的:

SELECT COLLATIONPROPERTY( 'Latin1_General_CI_AI' , 'CodePage' ) AS [CodePage]
--returns 1252

这个简单的 SQL 返回 COLLATIONWindows Code PageWindows Code Page不过是到 ENCODINGs的另一个映射。对于 Latin1_General_CI_AI COLLATION,它返回 Windows Code Page代码 1252,该代码映射到 Windows-1252 ENCODING
因此,对于使用 Latin1_General_CI_AI COLLATIONvarchar列,此字段将使用 Windows-1252 ENCODING处理其数据,并且只能正确地存储此编码支持的字符。

如果我们检查 Windows-1252 ENCODING规范 Windows-1252的字符列表,我们会发现这种编码不支持我们的表情符号字符。如果我们继续尝试:

A text containing UNICODE characters, wrongfully being stored, due our collation and encoding on the varchar field

好吧,那么我们怎样才能解决这个问题呢? 实际上,这要看情况,这很好!

NCHAR/NVARCHAR

在 SQLServer2019之前,我们只有 NCHARNVARCHAR字段。有人说它们是 UNICODE字段。这是不对的!.同样,它取决于字段的 COLLATION和 SQLServer 版本。 微软的 “ nchar 和 nvarchar (Transact-SQL)”文档完美地指出:

从 SQLServer2012(11.x)开始,当 使用启用了补充字符(SC)的排序规则时,这些数据 类别储存所有 Unicode字符资料,并使用 UTF-16字符编码。如果指定了非 SC 排序规则,则 这些数据类型只存储 UCS-2字符编码。

换句话说,如果我们使用比2012年更早的 SQL Server,比如 SQL Server 2008 R2,那么这些字段的 ENCODING将使用支持 UNICODE子集的 UCS-2 ENCODING。但是如果我们使用 SQL Server 2012或更新,并定义一个启用了 Supplementary CharacterCOLLATION,那么我们的字段将使用完全支持 UNICODEUTF-16 ENCODING


但是,还有更多! 我们现在可以使用 UTF-8! !

CHAR/VARCHAR

从 SQL Server 2019开始,我们可以使用 ABC0/VARCHAR字段仍然完全支持使用 UTF-8 ENCODINGUNICODE! ! !

来自微软的 “ char 和 varchar (Transact-SQL)”文档:

从 SQLServer2019(15.x)开始,当 使用启用 UTF-8的排序规则时,这些数据类型存储整个范围 Unicode字符数据,并使用 UTF-8字符编码 指定了 non-UTF-8排序规则,则这些数据类型只存储 的相应代码页所支持的字符子集 校对。

换句话说,如果我们使用比2019年更早的 SQL Server,例如 SQL Server 2008 R2,我们需要使用前面解释的方法检查 ENCODING。但是,如果我们使用 SQL Server 2019或更新的版本,并定义一个像 Latin1_General_100_CI_AS_SC_UTF8这样的 COLLATION,那么我们的字段将使用 UTF-8 ENCODING,它是目前为止最常用和最有效的编码,支持所有的 UNICODE字符。


奖金信息:

关于观察所对 我看到大多数欧洲语言(德语、意大利语、英语... ...)在 VARCHAR 列的同一数据库中都很好的观察,我认为很高兴知道为什么会这样:

对于最常见的 COLLATIONs,像默认的 Latin1_General_CI_AISQL_Latin1_General_CP1_CI_AS一样,ENCODING对于 varchar字段将是 Windows-1252。如果我们看看它的 文件,我们可以看到它支持:

英语,爱尔兰语,意大利语,挪威语,葡萄牙语,西班牙语,瑞典语 还有德语,芬兰语和法语。还有荷兰语,除了 IJ 这个字

但是正如我之前所说,这不是关于语言,而是关于你希望支持/存储哪些字符,如表情符号的例子,或者像“锂电池的电阻是0.5 Ω”这样的句子,我们再次使用简单的英语,还有一个希腊字母/字符“ omega”(在欧姆中表示电阻的符号) ,它不会被 Windows-1252 ENCODING正确处理。

结论:

就是这样!使用 char/ncharvarchar/nvarchar取决于您想要支持的字符,也取决于您的 SQL Server 的版本,它将决定哪个 COLLATIONsENCODINGs可用。




什么是联码、编码、校对和 UTF-8,以及它们是如何相互关联的
注: 以下解释均为 简化。请参考提供的文档链接,以了解有关这些概念的所有细节。

  • UNICODE -是一种标准,一种约定,旨在规范统一和有组织的表中的所有字符。在这个表中,每个字符都有一个唯一的数字。这个数字通常被称为字符的 code point。联码不是编码!

  • ENCODING -是字符和字节/字节序列之间的映射。因此,编码用于将字符“转换”为字节,反之亦然,从字节转换为字符。其中最受欢迎的是 UTF-8ISO-8859-1Windows-1252ASCII。你可以把它想象成一个“转换表”(这里我真的简化了)。

  • COLLATION -这个很重要。即使是微软的文档也没有清楚地表明这一点。排序规则指定如何对数据进行排序、比较、 储存起来!。是啊,我打赌你没想到最后一个,对吧?SQL Server上的排序也决定了在特定的 char/nchar/varchar/nvarchar字段上使用的 ENCODING是什么。

  • ASCII ENCODING -是最早的编码之一。它既是字符表(就像自己的小版本 UNICODE) ,也是它的字节映射。所以它不会将一个字节映射到 UNICODE,而是将一个字节映射到它自己的字符表。此外,它始终只使用7位,并支持128个不同的字符。它足以支持所有的英文字母大小写,数字,标点符号和其他一些有限的字符。ASCII 的问题在于,由于它只使用7位,而且当时几乎每台计算机都是8位,因此还有128种可能的字符需要“探索”,每个人都开始将这些“可用”字节映射到自己的字符表中,创建了许多不同的 ENCODINGs

  • UTF-8 ENCODING -这是另一个 ENCODING,是使用最多(如果不是最多)的 ENCODING之一。它使用可变字节宽度(根据规范,一个字符的长度可以从1到6个字节) ,并完全支持所有 UNICODE字符。

  • Windows-1252 ENCODING -也是最常用的 ENCODING之一,在 SQL Server 上得到了广泛的应用。它是固定大小的,所以每个字符总是1字节。它还支持许多口音,来自不同的语言,但不支持所有现有的,也不支持 UNICODE。< em > 这就是为什么 varchar字段使用像 Latin1_General_CI_AS这样的常见排序规则支持 áéñ字符,即使它没有使用支持的 UNICODE ENCODING

资源:
Https://blog.greglow.com/2019/07/25/sql-think-that-varchar-characters-if-so-think-again/
Https://medium.com/@apiltamang/unicode-utf-8-and-ascii-encodings-made-easy-5bfbe3a1c45a
Https://www.johndcook.com/blog/2019/09/09/how-utf-8-works/
Https://www.w3.org/international/questions/qa-what-is-encoding

Https://en.wikipedia.org/wiki/list_of_unicode_characters
Https://www.fileformat.info/info/charset/windows-1252/list.htm

Https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver15
Https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver15
Https://learn.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql?view=sql-server-ver15
Https://learn.microsoft.com/en-us/sql/t-sql/statements/sql-server-collation-name-transact-sql?view=sql-server-ver15
Https://learn.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver15#sql-collations

SQL Server 默认字符编码
Https://en.wikipedia.org/wiki/windows_code_page