代码之家  ›  专栏  ›  技术社区  ›  Peter Gfader

在SQL Server中何时必须使用NVARCHAR/NCHAR而不是VARCHAR/CHAR?

  •  63
  • Peter Gfader  · 技术社区  · 17 年前

    当我们必须使用Unicode类型时,有规则吗?

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

    1. 如果你有中文-->使用NVARCHAR

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

    What are the main performance differences between varchar and nvarchar SQL Server data types?

    5 回复  |  直到 9 年前
        1
  •  119
  •   Cade Roux    8 年前

    您想要使用NVARCHAR的真正原因是当您 不同的 在同一列中,您需要在T-SQL中寻址列而无需解码,您希望能够在SSMS中“本地”查看数据,或者您希望在Unicode上实现标准化。

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

    使用NVARCHAR可以避免所有这一切。

    我建议NVARCHAR用于任何一列,其中包含用户输入的数据,并且相对不受限制。

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

    保证受约束时的VARCHAR NVARCHAR否则

        2
  •  16
  •   Vitox stevehipwell    6 年前

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


    你应该使用 NVARCHAR NCHAR 每当 ENCODING 校勘 字段的,不支持所需的字符。
    COLLATIONs 喜欢 Latin1_General_100_CI_AS_SC_UTF8 VARCHAR 字段(或整个表/数据库)将使用 UTF-8 编码 UNICODE 字符,以及它所包含的任何语言。


    要充分理解:
    统一码 , 和 你头脑中的一切都非常清楚。如果您不知道,那么首先看看下面我对“什么是UNICODE、编码、排序规则和UTF-8,以及它们之间的关系”一节和提供的文档链接所做的简略解释。而且,我在这里说的每一句话都是针对 Microsoft SQL Server ,以及它如何在中存储和处理数据 char / nchar 瓦尔查尔 / nvarchar 领域。


    即使ASCII也完全支持纯英语部分,但因为还有一个表情符号,这是在 标准,我们需要一个 编码

    校勘 决定什么 用于 烧焦 / 固定长度 / / 领域。所以,和很多人想象的不同, 校勘 不是 不仅是关于排序和比较数据,还包括 编码 ,因此:

    所以 我们如何知道排序规则使用的编码是什么?

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

    这个简单的SQL返回 Windows Code Page 暂时 校勘 . A. Windows代码页 ENCODINGs . 对于 Latin1_General_CI_AI 校勘 Windows代码页 密码 1252 ,这映射到 Windows-1252 编码
    那么,为了一个 列,带 拉丁语1_General_CI_AI 校勘 ,此字段将使用 Windows-1252 编码 ,并且仅正确存储此编码支持的字符。

    Windows-1252 ENCODING 规格 Character List for Windows-1252 ,我们将发现此编码不支持我们的表情符号。如果我们仍然尝试:

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

    事实上,这要看情况而定,这很好!

    恩查尔 /

    在SQL Server 2019之前,我们只有 恩查尔 和 领域。有人说是的 统一码 那是错误的! . 同样,这取决于现场的温度 以及SQLServer版本。 微软的 "nchar and nvarchar (Transact-SQL)" documentation

    从SQL Server 2012(11.x)开始,当 如果使用支持补充字符(SC)的排序规则,这些数据 类型存储全部Unicode字符数据,并使用 这些数据类型仅存储 UCS-2字符编码。

    换句话说,如果我们使用2012年以前的SQL Server,例如SQL Server 2008 R2 编码 对于这些字段,将使用 UCS-2 ENCODING 它们支持 统一码 . 但如果我们使用SQL Server 2012或更新版本,并定义 校勘 那已经 Supplementary Character 已启用,则我们的字段将使用 UTF-16 编码 统一码


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

    CHAR /

    从SQL Server 2019开始, 我们可以使用 烧焦 / 各领域仍然全力支持 统一码 使用 编码

    来自微软的 "char and varchar (Transact-SQL)" documentation

    从SQL Server 2019(15.x)开始 如果使用启用UTF-8的排序规则,这些数据类型将存储整个范围 并使用UTF-8字符编码。如果 如果指定了非UTF-8排序规则,则这些数据类型仅存储 对应代码页支持的字符子集

    同样,换句话说,如果我们使用2019年以前的SQL Server,比如SQL Server 2008 R2,我们需要检查 编码 校勘 拉丁语1\u通用\u 100\u CI\u AS\u SC\u UTF8 ,那么我们的领域将使用 UTF-8 人物。


    奖金信息:

    关于OP对 ,我觉得很高兴知道原因:

    最常见的 校勘 ,与默认值类似 拉丁语1_General_CI_AI 或 SQL_Latin1_General_CP1_CI_AS 编码 Windows-1252 对于 领域。如果我们看一下它的 documentation ,我们可以看到它支持:

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

    但正如我之前所说,这与语言无关,而是与你希望支持/存储哪些字符有关,如表情符号示例所示,或者类似“锂电池的电阻为0.5”这样的句子,其中我们再次使用了简单的英语和希腊字母/字符“omega”(欧姆表示电阻的符号),这将不会被正确处理

    结论:

    原来是这样!使用时 / 固定长度 和 瓦尔查尔 / 取决于要支持的字符,以及将决定支持哪个字符的SQL Server版本 编码 你有空。




    什么是UNICODE、编码、排序规则和UTF-8,以及它们之间的关系
    注:以下所有解释均为

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

    • 编码 -是字符和字节/字节序列之间的映射。因此,编码用于将字符“转换”为字节,反之亦然,即从字节转换为字符。其中最受欢迎的是 UTF-8 ISO-8859-1 , Windows-1252 ASCII . 您可以将其视为“转换表”(我在这里进行了简化)。

    • 校勘 -这一点很重要。即使是微软的文档也没有把这一点说清楚。排序规则指定如何对数据进行排序、比较, 和存储! . 是的,我打赌你没想到最后一个,对吧!?校勘 SQL Server 也决定了什么是 编码 用在那个特殊的地方 / 固定长度 / / nvarchar

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

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

    • Windows-1252编码 -也是最常用的方法之一 编码 ,它在SQL Server上被广泛使用。它的大小是固定的,所以每个字符都是1字节。它还支持多种语言的口音,但不支持所有现有的口音,也不支持 统一码 这就是为什么你的 拉丁语1_General_CI_AS 支持 á é ± 角色,即使它没有使用支持 编码 .

    资源:
    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://docs.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver15
    https://docs.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver15
    https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql?view=sql-server-ver15
    https://docs.microsoft.com/en-us/sql/t-sql/statements/sql-server-collation-name-transact-sql?view=sql-server-ver15
    https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver15#SQL-collations

    SQL Server default character encoding
    https://en.wikipedia.org/wiki/Windows_code_page

        3
  •  11
  •   JoshBerke    17 年前

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

    MSDN maybee我说得很具体,但您不想在varcar列中存储超过一个代码页,而您可以,但您不应该

    在处理文本数据时 存储在char,varchar, 这仅仅是来自一个单一国家的信息吗 系统(您可以从中存储数据 多个代码页,但这不是 关于列的排序规则。如果 尚未创建列级排序规则 已定义,数据库的排序规则 使用。确定代码页的步骤 用于给定列的,您可以 函数,如下所示 代码示例:

    这个例子说明了以下事实: 许多地区,如格鲁吉亚和土耳其 只有Unicode排序规则。那些 使用char、varchar或 文本数据类型

    您可能遇到的另一个问题是 无法在不可用时存储数据 支持包含在代码中 页在许多情况下,Windows会考虑 “适合”代码页,这意味着 不能保证您可以依赖 代码页处理所有文本;它是 只是最好的一个。一 阿拉伯语脚本就是一个例子: 它支持多种语言, 包括俾路支、柏柏尔、波斯语、, 克什米尔、哈萨克、吉尔吉斯、普什图、, 信德、维吾尔、乌尔都语等等。全部 这些语言有额外的功能 阿拉伯语以外的字符 Windows代码中定义的语言 第1256页。如果您试图存储 这些额外的字符 具有阿拉伯语字符的非Unicode列 排序规则,字符是 转换成问号。

    总之,在处理内部化时,你必须处理所有的问题。我的观点是,从一开始就使用Unicode字符更容易,避免额外的转换并占用空间。因此,我早些时候发言。

        4
  •  4
  •   cherouvim    17 年前

    希腊文在N列类型上需要UTF-8:±;)

        5
  •  2
  •   Alex    17 年前

    “…当您使用Unicode时,请记住一点,尽管您可以在单个列中存储不同的语言,但您只能使用单个排序规则进行排序。有些语言使用拉丁字符,但排序方式与其他拉丁语言不同。口音就是一个很好的例子,我记不起这个例子了,但有一个东方口音。”opean是一种语言,它的Y排序方式与英语的Y排序方式不同。然后是西班牙语的ch,西班牙语用户要求它在h之后排序。”

    我们不希望在“h”之后加上“ch”,而是“i” 字母表与英语中的字母表相同,但Ã或HTML中的“ñ”除外

    亚历克斯

        6
  •  0
  •   Matas Vaitkevicius user3782709    10 年前

    TL;博士

    From MSDN

    SQL Server中的排序规则提供排序规则、大小写和重音 数据的灵敏度属性。与一起使用的排序规则 字符数据类型(如char和varchar)指示代码页 以及可以为该数据表示的相应字符

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

    否则你的分类会很奇怪。

        7
  •  0
  •   Umar Farooq    6 年前

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

    推荐文章