varchar和nvarchar有什么区别?

1684

nvarchar 是不是只支持多字节字符?如果是这样,使用 varchar 除了存储方面的考虑外,是否还有其他意义呢?


6
我喜欢incomudro的观点,这让我开始查找varchar和nvarchar之间的区别。我们的Java应用程序连接SQL Server数据库使用myBatis,默认情况下发送字符串作为nvarchar(仍然不确定是否可以覆盖)。因为我定义了一个选择varchar而不是nvarchar类型列,导致一个简单的查询变成了一个严重的性能问题,它忽略了该列上的索引。 - Sean Read
21个回答

2113

nvarchar列可以存储任何Unicode数据,而varchar列仅限于8位代码页。有些人认为使用varchar可以节省空间,但我认为这不是正确的答案。代码页不兼容往往会带来麻烦,而Unicode则可解决这种问题。如今磁盘和内存价格便宜,没有必要再浪费时间用代码页来操作。

所有现代操作系统和开发平台都在内部使用Unicode。如果使用nvarchar而不是varchar,你就可以避免每次读取或写入数据库时进行编码转换。转换需要时间,而且容易出错。而处理转换错误是一个棘手的问题。

即使与只使用ASCII的应用程序进行接口交互,我仍建议在数据库中使用Unicode。操作系统和数据库排序算法将更好地与Unicode配合使用。使用Unicode避免了与其他系统交互时的转换问题。而且你将为未来做好准备。即使在维护某个历史系统时需要将数据限制为7位ASCII,你仍可以享受完全Unicode存储的一些好处,并验证你的数据是否符合要求。


11
这是很有价值的信息。如果我推断出,最终的选择成为哪种资源更便宜:处理器+开发费用还是存储费用,那么我的理解是正确的吗? - Matt Cashatt
178
你可以这样理解。但如果你想象一个美好的世界,在那里所有的文本数据都是Unicode格式,并且开发人员永远不必考虑某个东西使用的编码方式,一整类错误就会消失,那么你会发现实际上并没有其他选择。 - Jeffrey L Whitledge
22
在所有字符集中,varchar 并不局限于 8 位代码页。 - Martin Smith
10
在这些情况下,varchar带来的微小优势(紧凑的存储)会消失。我想varchar甚至比我想象的还要糟糕! - Jeffrey L Whitledge
9
@PeterAllenWebb - 你可以“存储”任何Unicode数据,因为UTF-16中的代理对可以像字符一样存储在UCS-2中。这对于数据存储和检索来说是透明的。但是,在BMP之外获得可靠的大小写转换和比较是不可能的,但我没有声称过能够做到这一点。因此,如果您有大量Desseret文本需要处理,最好在数据库之外进行处理。但是将其存储在数据库中就完全没问题。(当然,varchar也无法帮助您!) - Jeffrey L Whitledge
显示剩余17条评论

307

varchar: 可变长度的非 Unicode 字符数据。数据库排序规则决定了使用哪个代码页存储数据。

nvarchar: 可变长度的 Unicode 字符数据。与数据库排序规则相关,用于比较。

掌握这些知识后,根据输入数据(ASCII 或 Unicode)使用匹配的字符类型。


5
varchar 存储 Unicode 数据有限制吗?其实它只是由 1 和 0 组成的。我可以将中文内容保存为 varchar 到我的数据库中,只需指定其为 UTF-8 即可。那么它是如何工作的呢? - Nishant
5
当然可以在varchar中存储UTF-8,但它会破坏SQL Server字符串函数。如果你在应用程序内执行所有搜索/转换操作,那么可以这样做(但有什么好处吗?)。 SQL Server支持的唯一Unicode编码是UCS-2(是的,在SS2k16之前不是UTF-16),其字符串函数仅适用于该编码。另外,关于索引呢?如果你想存储任意数据,最好使用二进制。 - Adriano Repetti
1
是的,它只是破坏了字符串搜索函数。 - Nishant
17
所以,你知道的...它不“起作用”。这就像将一个float存储到一个int中,然后说,“当然,小数点会丢失。” 不要这样做。 - user7116
可能在电子商务平台上,您事先知道可以使用varchar仅限英语或“标准”西方名称的类别内容,而在其他地方,例如名称、位置、产品描述内容,nvarchar将是更好的选择。 - Eve

82

我总是使用nvarchar,因为它可以让我构建的任何系统承受几乎任何数据。我的CMS系统意外地支持中文,因为我使用了nvarchar。如今,任何新应用程序不应太关心所需的空间量。


42
认为新应用程序不必考虑空间限制的想法有些短视,任何在中大型企业级别上处理数据库的人都会很高兴地告诉你,这是完全不正确的。 - Frater
87
请允许我添上一些话,我认为更准确的说法可能是“现在任何新应用程序更应该关注国际化和其他字符集问题,而不是空间需求。” - Cowan
2
现在,任何新的应用程序都不应该真正关心所需的存储空间。除非您使用免费的云存储,否则付费计划会有相当大的价格差距(请参见AppHarbor SQL Server共享计划)。 - ganders
4
@ganders 嗷呜!你说得对。泛泛而谈的陈述最多只是暂时正确的。计算机确实是一个充满起伏的游戏。我一定会关注我在Windows Azure CCP上使用了多少空间。话虽如此,我“永远”不会使用 varchar 而放弃使用 nvarchar。哦,我刚刚自相矛盾了吗? - rism
1
@rism,我相信你在引用“never”时消除了任何矛盾的风险,至少从技术上来说。 - Smandoli
显示剩余2条评论

35
这取决于Oracle是如何安装的。在安装过程中,NLS_CHARACTERSET选项被设置。您可以使用查询SELECT value$ FROM sys.props$ WHERE name = 'NLS_CHARACTERSET'找到它。
如果您的NLS_CHARACTERSET是像UTF8这样的Unicode编码,那么很好。使用VARCHAR和NVARCHAR基本上是相同的。现在停止阅读,只需去做。否则,或者如果您无法控制Oracle字符集,请继续阅读。
VARCHAR - 数据存储在NLS_CHARACTERSET编码中。如果在同一服务器上有其他数据库实例,则可能会受到限制;反之亦然,因为您必须共享设置。此类字段可以存储使用该字符集进行编码的任何数据,但不能存储其他数据。因此,例如,如果字符集是MS-1252,则只能存储像英文字母、一些重音字母和一些其他字符(如€和—)等字符。您的应用程序仅对少数语言环境有用,无法在世界上其他地方运作。因此,它被认为是不良的想法。
NVARCHAR - 数据存储在Unicode编码中。支持所有语言。这是一个好主意。
存储空间怎么样?VARCHAR通常效率高,因为字符集/编码是针对特定区域设置进行自定义设计的。NVARCHAR字段存储在UTF-8或UTF-16编码中,取决于NLS设置,具有讽刺意味。对于“西方”语言,UTF-8非常高效,同时还支持亚洲语言。对于亚洲语言,UTF-16非常高效,同时还支持“西方”语言。如果担心存储空间,请选择一个NLS设置,以使Oracle根据需要使用UTF-8或UTF-16。
处理速度怎么样?大多数新编码平台本地使用Unicode(Java、.NET,甚至是多年前的C++ std::wstring!)因此,如果数据库字段是VARCHAR,则强制Oracle在每次读取或写入时转换字符集,情况并不好。使用NVARCHAR避免了这种转换。
底线:使用NVARCHAR!它避免了限制和依赖性,在存储空间上很好,在性能上也通常是最好的选择。

55
这是一个非常好的答案,不过问题是关于SQL Server的。 - stimms
最佳答案。我使用varchar2,因为我的数据库字符集是al32utf8。 - lalilulelo_1986

31

nvarchar以Unicode的格式存储数据,因此如果您要在数据列中存储多语言数据(超过一种语言),则需要使用N variant。


28

VARCHAR 仅用于非 Unicode 字符,而 NVARCHAR 则可用于 Unicode 和非 Unicode 字符。它们之间的一些其他差异如下所述。

VARCHAR vs. NVARCHAR

VARCHAR NVARCHAR
字符数据类型 可变长度的非 Unicode 字符 可变长度的 Unicode 和非 Unicode 字符(例如日语、韩语和中文)
最大长度 最多可包含8,000个字符 最多可包含4,000个字符
字符大小 每个字符占用1个字节 每个 Unicode/非 Unicode 字符占用2个字节
存储空间大小 实际长度(以字节为单位) 实际长度的 2 倍(以字节为单位)
用途当数据长度可变或存在可变长度列,且实际数据总是远小于容量时使用该选项 由于存储原因,仅在需要Unicode支持(如日语假名或韩语汉字)时使用该选项。

26

Varchar(n)nvarchar(n) 的主要区别在于:

enter image description here

Varchar (可变长度,非 Unicode 字符数据)的大小为最多 8000 个字符。

  1. 它是一种可变长度的数据类型。
  2. 用于存储非 Unicode 字符。
  3. 每个字符占用 1 个字节的空间。

enter image description here

Nvarchar: 可变长度 Unicode 字符数据。

  1. 它是一种可变长度的数据类型。
  2. 用于存储 Unicode 字符。
  3. 数据以 Unicode 编码存储。支持所有语言。(例如阿拉伯语、德语、印地语等等)

21

自SQL Server 2019起,varchar列支持UTF-8编码。

因此,从现在开始,差异在于大小。

在一个数据库系统中,这意味着速度的差异。

更少的数据 = 更少的IO + 更少的内存 = 总体上更快的速度。请参阅上述文章了解详细数据。

从现在开始,请使用 UTF8中的varchar!

只有当您的数据中大约占比较高的字符范围为2048-16383和16384-65535时,您才需要进行测量。


3
一个极为被低估的答案。我想知道有多少新数据库会使用nvarchar,因为某个工程师仅仅看了2008年的最佳回答。 - kamilk
1
UTF8有一些限制,你不能在OLTP(SQLServer 2019)中使用该排序规则,因此如果MEMORY_OPTIMIZED表和过程的NATIVE_COMPILATION是必需的,最好不要依赖UTF8。 - ColdCat
@kamilk,不是被低估了,只是不那么有用。我们中有很多人处理旧的SQL平台,这些平台不支持该行为。现在是2019年,而且世界比你想象的要大。在许多需要产品国际化功能的情况下,UTF8太小了。IO很便宜,因此NVARCHAR是更优选的选项。 - zu1b

20

我的两分钱

  1. 当使用错误的数据类型时,索引可能会失效:
    在SQL Server中,如果你对一个VARCHAR列创建了索引并提供给它一个Unicode字符串,那么SQL Server将无法使用该索引。同样的情况也会出现在当你将BigInt提供给一个包含SmallInt的索引列时。即使BigInt的大小足够小以适应SmallInt,SQL Server仍然无法使用该索引。反过来则没有这个问题(当提供SmallInt或Ansi-Code至一个indexed BigInt或NVARCHAR列时)。

  2. 不同的DBMS(数据库管理系统)可能具有不同的数据类型:
    请注意,每个数据库都有略微不同的数据类型,VARCHAR在各个数据库中的含义并不相同。虽然SQL Server有VARCHAR和NVARCHAR,但Apache/Derby数据库只有VARCHAR,且VARCHAR是以Unicode编码的。


但是如果你正确编写代码(即使用参数化查询等),那么第一点的风险就会降低。 - user1945782

18

主要nvarchar存储Unicode字符,varchar则存储非Unicode字符。

"Unicode" 是一种16位字符编码方案,允许将来自许多其他语言的字符(如阿拉伯语、希伯来语、中文、日语)编码为单个字符集。

这意味着每个Unicode字符需要使用2个字节进行存储,而每个非Unicode字符只需使用一个字节进行存储。这意味着相比于非Unicode字符,Unicode字符需要双倍的容量来存储。


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