SQL国家字符(NCHAR)数据类型的真正作用是什么?

57
除了 CHAR (字符)VARCHAR (可变长度字符),SQL 还提供了 NCHAR (国家字符)NVARCHAR (国家字符可变长度) 类型。在一些数据库中,这是更好的数据类型来存储字符(非二进制)字符串:

  • 在 SQL Server 中,NCHAR 以 UTF-16LE 的形式存储,是可靠地存储非 ASCII 字符的唯一方式,而 CHAR 则仅使用单字节编码页;

  • 在 Oracle 中,NVARCHAR 可以存储为 UTF-16 或 UTF-8,而不是单字节排序;

  • 但在 MySQL 中,NVARCHARVARCHAR,因此没有区别,任何一种类型都可以使用 UTF-8 或其他排序存储。

那么,“NATIONAL” 究竟代表什么概念,或者是否代表任何概念呢?供应商的文档只告诉您他们自己的 DBMS 使用的字符集,而不是实际的基本原理。同时, SQL92 标准对此功能的解释也没有太大帮助,仅说明 NATIONAL CHARACTER 存储在实现定义的字符集中。而不是一个简单的 CHARACTER,后者存储在实现定义的字符集中。这可能是另一个实现定义的字符集。也可能不是。

谢谢,ANSI. 万谢。

是否应该对所有字符(非二进制)存储使用 NVARCHAR?目前流行的 DBMS 中是否存在会导致它执行不良操作或根本无法识别关键字(或 N'' 文本)的情况?


4
SQL Server将NVARCHAR存储在UCS-2编码中,而不是UTF-16中:http://msdn.microsoft.com/en-us/library/bb330962(SQL.90).aspx#intlftrql2005_topic2 - Remus Rusanu
1
@bobince,"Thansi" 是什么意思? - Pacerier
5
希望这可以帮到你。 - bobince
3个回答

17
在这种情况下,“NATIONAL”表示特定于不同国籍的字符。远东语言尤其有许多字符,一个字节的空间不足以区分它们。因此,如果您有一个只使用英语(ascii)的应用程序或者一个只使用英语的字段,您可以使用旧的CHAR和VARCHAR类型,这些类型只允许每个字符使用一个字节的空间。
尽管如此,大多数情况下,您应该使用NCHAR/NVARCHAR。即使您认为您的数据不需要支持(或可能支持)多种语言,即使是仅限英语的应用程序也需要能够明智地处理使用外语字符的安全攻击。
在我看来,旧的CHAR/VARCHAR类型仍然被认为是首选的唯一场景是对于像SQL Server这样支持区分的频繁引用的ascii-only内部代码和数据,这些数据相当于客户端语言如C++或C#中的枚举。

6
我不同意。在SQL Server中使用nvarchar会对性能产生巨大的影响。如果您不需要它,请不要使用它。参考链接:https://dev59.com/9XVD5IYBdhLWcg3wQZUg#198753 - gbn
3
确实存在性能问题,但我认为正确性问题往往比它们更重要。 - Joel Coehoorn
正确性就是使用所需的数据类型。例如,ISO货币代码应为char(3),不需要任何其他操作。 - gbn

5
与此同时,SQL92标准对该特性的解释不太有帮助,仅说明NATIONAL CHARACTER存储在一个实现定义的字符集中。相比之下,CHARACTER只是存储在一个实现定义的字符集中。这可能是一个不同的实现定义的字符集。也可能不是。
巧合的是,C++标准对char和wchar_t之间也做出了同样的“区分”。这是字符编码黑暗时代的遗留问题,每种语言/操作系统组合都有其自己的字符集。
是否应该将NVARCHAR用于所有字符(非二进制)存储目的?
重要的不是列的声明类型是VARCHAR还是NVARCHAR,而是在所有字符存储目的中使用Unicode(无论是UTF-8、UTF-16还是UTF-32)。
当前流行的DBMS中是否存在会产生不良影响的情况?

是的:在MS SQL Server中,使用NCHAR会使您的(英文)数据占用两倍的空间。不幸的是,UTF-8尚未得到支持。

编辑:SQL Server 2019终于引入了UTF-8支持


2
我想的更多是不支持的特性不受欢迎或查询失败不受欢迎,而不仅仅是效率问题,但我认为这也是正确的!那么你能说一下在黑暗时代提出CHARNCHAR之间所需的区别吗?据我了解,忽略wchar_t在内存中的存储方式,wchar_t的整个意义在于提供代码点语义(自然后来可能是UTF-16代码单元语义),而NCHAR似乎并没有固有地保证代码点、代码单元或字节语义,只是一种“不同”的编码。 - bobince
这不仅仅是关于存储的问题 https://dev59.com/9XVD5IYBdhLWcg3wQZUg#198753 - gbn

3
在Oracle中,数据库字符集可以是多字节字符集,因此您可以在其中存储各种字符...但是您需要适当地理解和定义列的长度(以字节或字符为单位)。
NVARCHAR使您可以选择具有单字节的数据库字符集(这减少了BYTE或CHARACTER大小列之间混淆的可能性),并将NVARCHAR用作多字节字符集。请参见here
由于我主要使用英语数据,我会选择多字节字符集(主要是UTF-8)作为数据库字符集,并忽略NVARCHAR。如果我继承了一个旧的数据库,它处于单字节字符集中并且太大而无法转换,那么我可能会使用NVARCHAR。但我宁愿不这样做。

即使您正在处理“英文数据”,通常仍需要关注非英文字符。人名是“英语系统”中非英文字符的常见示例,但还有其他情况。 - HappyDog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接