varchar 和 nvarchar 有什么区别?

What is the difference between varchar and nvarchar?

提问人:stimms 提问时间:9/28/2008 最后编辑:Peter Mortensenstimms 更新时间:7/21/2022 访问量:1499820

问:

只是支持多字节字符吗?如果是这样的话,除了存储问题之外,真的有什么意义吗?nvarcharvarchars

sql-server varchar nvarchar

评论

7赞 Sean Read 5/3/2013
我喜欢 incomudro 的观点,它首先促使我挖掘 varchar 和 nvarchar 之间的区别。我们针对 SQL Server 数据库的 Java 应用程序使用 myBatis,它似乎默认将字符串作为 nvarchar 发送(仍然不确定如何(或是否)可覆盖)。一个简单的查询显示为一个巨大的性能问题,因为我已将它选择的列定义为 varchar,而不是 nvarchar,并且它忽略了该列的索引。

答:

11赞 Vijesh VP 9/28/2008 #1

nVarchar 将帮助您存储 Unicode 字符。如果要存储本地化数据,这是要走的路。

31赞 albertein 9/28/2008 #2

nvarchar 将数据存储为 Unicode,因此,如果要在数据列中存储多语言数据(多种语言),则需要 N 变体。

307赞 user7116 9/28/2008 #3

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

nvarchar:可变长度的 Unicode 字符数据。依赖于数据库排序规则进行比较。

掌握了这些知识后,请使用与您的输入数据匹配的任何一个(ASCII v. Unicode)。

评论

5赞 Nishant 9/24/2014
是否有像 varchar 无法存储 Unicode 数据这样的限制?它都是 1 和 0 .我能够将中文内容保存为 varchar 到我的数据库中。我只是指定它的 UTF-8 .那它是如何工作的呢?
5赞 Adriano Repetti 9/9/2015
@Nishant迟到的答案:当然,您可以将 UTF-8 存储在 varchar 中,但它会破坏 SQL Server 字符串函数。如果您在应用程序中执行所有搜索/转换,那么是的,您可以这样做(但有什么好处?SS 支持的唯一 Unicode 编码是 UCS-2(是的,不是 SS2k16 之前的 UTF-16),其字符串函数仅适用于该编码。顺便说一句,指数呢?如果要存储任意数据,最好使用二进制文件。
1赞 Nishant 9/11/2015
是的,它只是破坏了字符串搜索函数。
17赞 user7116 9/12/2015
所以,你知道......它不“工作”。这就像将 a 存储到 an 中,然后说,“当然小数点不见了。只是不要。floatint
0赞 Eve 12/14/2021
可能在您事先知道类别内容的电子商务平台中,可以将 varchar 用于仅英文或“标准”西方名称,而在您有名称、位置、产品描述内容的其他地方,nvarchar 将是更好的选择
82赞 tags2k 9/28/2008 #4

我总是使用 nvarchar,因为它允许我正在构建的任何东西都能承受我扔给它的几乎任何数据。我的 CMS 系统是偶然的,因为我使用了 nvarchar。如今,任何新应用程序都不应该真正关心所需的空间量。

评论

42赞 Frater 7/21/2010
认为新应用程序不应该关注空间限制的想法有些短视,任何在大中型企业级别处理过数据库的人都会很乐意告诉你,这是完全不正确的。
87赞 Cowan 10/16/2010
为了冒昧地把话塞进tags2k的嘴里,我认为更准确的说法可能是“任何新应用程序都不太可能更多地关注所需的空间,而不是国际化和其他字符集问题”。
2赞 ganders 6/6/2014
“如今,任何新应用程序都不应该真正关心所需的空间量。 - 除非您使用的是免费的云存储,否则付费计划的价格大幅增加(请参阅 AppHarbor SQL Server 共享计划)。
4赞 rism 6/8/2014
@ganders嚎叫!你就在那里。笼统的陈述充其量只是暂时正确的。计算绝对是一个摇摆不定和迂回的游戏。我绝对关心我在 Windows Azure CCP 上使用多少空间。也就是说,我“永远不会”使用 varchar 而不是 nvarchar。哎呀,我只是自相矛盾吗?
1赞 Smandoli 11/6/2014
@rism,我相信您消除了使用引号的任何矛盾风险,至少在技术上是这样。"never"
13赞 Mike Spross 9/28/2008 #5

你是对的。 存储 Unicode 数据,同时存储单字节字符数据。除了您已经提到的存储差异(需要两倍的存储空间)之外,首选的主要原因是国际化(即以其他语言存储字符串)。nvarcharvarcharnvarcharvarcharnvarcharvarchar

2115赞 Jeffrey L Whitledge 9/29/2008 #6

列可以存储任何 Unicode 数据。列限制为 8 位代码页。有些人认为应该使用它,因为它占用的空间更少。我相信这不是正确的答案。代码页不兼容是一种痛苦,而 Unicode 是解决代码页问题的良方。如今,由于磁盘和内存价格低廉,因此真的没有理由再浪费时间在代码页上乱七八糟了。nvarcharvarcharvarchar

所有现代操作系统和开发平台都在内部使用 Unicode。通过使用 而不是 ,可以避免每次读取或写入数据库时都进行编码转换。转换需要时间,并且容易出错。从转换错误中恢复是一个不平凡的问题。nvarcharvarchar

如果您要与仅使用 ASCII 的应用程序进行交互,我仍然建议在数据库中使用 Unicode。操作系统和数据库排序规则算法将更好地与 Unicode 配合使用。Unicode避免了与其他系统连接时的转换问题。你将为未来做准备。而且,对于您必须维护的任何遗留系统,您始终可以验证您的数据是否仅限于 7 位 ASCII,即使在享受完整 Unicode 存储的一些好处时也是如此。

评论

11赞 Matt Cashatt 1/15/2012
这是一个很好的信息。那么,如果我推断出选择最终成为哪种资源更便宜:处理器 + 开发开销还是存储,我是否正确理解了这一点?
179赞 Jeffrey L Whitledge 1/19/2012
@MatthewPatrickCashatt - 你可以这样看。但是,如果你想象一个光荣的世界,在这个世界里,所有的文本数据都是Unicode的,开发人员根本不需要考虑什么编码,而且一整类错误根本不会发生,那么你就会发现,真的别无选择。
10赞 Jeffrey L Whitledge 2/6/2012
@Martin Smith - 在这些情况下,varchar 带来的微小优势(紧凑存储)消失了。我想 varchar 比我想象的还要糟糕!
9赞 Jeffrey L Whitledge 6/27/2013
@PeterAllenWebb - 您可以“存储”任何 Unicode 数据,因为 UTF-16 中的代理项对可以像字符一样存储在 UCS-2 中。这将透明地用于数据存储和检索。现在,你不能做的是在 BMP 之外获得可靠的案例转换和比较,但我没有对此提出任何要求。因此,如果您想要对大量 Desseret 文本进行处理,最好在数据库之外进行处理。但是把它存放在那里就好了。(当然,varchar 也不会在那里帮助你!
11赞 sleepy012 1/25/2010 #7

我会说,这要看情况。

如果您开发一个桌面应用程序,其中操作系统以 Unicode 工作(与所有当前的 Windows 系统一样),并且语言本身支持 Unicode(默认字符串为 Unicode,如 Java 或 C#),则转到 nvarchar。

如果您开发一个 Web 应用程序,其中字符串以 UTF-8 形式出现,语言是 PHP,它仍然不支持 Unicode(在 5.x 版本中),那么 varchar 可能是更好的选择。

35赞 Jeremy Frank 10/8/2010 #8

这取决于 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赞 stimms 10/8/2010
这是一个非常好的答案,除了问题是关于 sql-server 的。
0赞 lalilulelo_1986 8/12/2021
最佳答案。我正在使用 varchar2,因为我的数据库字符集是 al32utf8
18赞 ranjit pawar 12/14/2011 #9

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

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

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

20赞 incomudro 4/19/2013 #10

我的两分钱

  1. 未使用正确的数据类型时,索引可能会失败: 在 SQL Server 中:
    如果对 VARCHAR 列有索引并向其提供 Unicode 字符串,则 SQL Server 不会使用该索引。当您将 BigInt 呈现给包含 SmallInt 的索引列时,也会发生同样的事情。即使 BigInt 足够小,可以成为 SmallInt,SQL Server 也无法使用该索引。反之,您不会遇到此问题(当向索引的 BigInt 或 NVARCHAR 列提供 SmallInt 或 Ansi-Code 时)。

  2. 数据类型可能因不同的 DBMS(数据库管理系统)而异:
    要知道每个数据库的数据类型略有不同,并且 VARCHAR 并不意味着任何地方都一样。虽然 SQL Server 具有 VARCHAR 和 NVARCHAR,但 Apache/Derby 数据库只有 VARCHAR,而 VARCHAR 采用 Unicode。

评论

0赞 11/20/2013
但可以肯定的是,如果你正确地编写了代码(即使用参数化查询等),那么第 1 点的风险就更小了。
6赞 user1945782 11/20/2013 #11

我不得不在这里说(我意识到我可能会向 slating 敞开心扉!),但可以肯定的是,唯一一次实际上所有依赖系统和数据库本身中的所有排序规则都相同时更有用(注意那里更多!)......?如果不是,那么无论如何都必须进行排序规则转换,因此与 一样可行。NVARCHARVARCHARVARCHARNVARCHAR

除此之外,一些数据库系统,如 SQL Server(2012 年之前)的页面大小约为 8K。因此,如果您正在考虑存储未保存在 or 字段中的可搜索数据,那么将提供完整的 8k 空间,而仅提供 4k(双倍的字节,双倍的空间)。TEXTNTEXTVARCHARNVARCHAR

我想,总而言之,两者的使用都取决于:

  • 项目或上下文
  • 基础设施
  • 数据库系统
6赞 Pradeep Kesharwani 1/30/2014 #12

遵循 Sql Server VARCHAR 和 NVARCHAR 数据类型之间的区别。在这里,你可以以一种非常描述性的方式看到。

通常nvarchar 将数据存储为 Unicode,因此,如果要在数据列中存储多语言数据(多种语言),则需要 N 变体。

评论

0赞 RubberDuck 10/8/2014
这是一个非常有用的链接,但你的答案并不多于此:一个链接。
0赞 Pradeep Kesharwani 10/8/2014
ckuhn203 ,我不会告诉你看这个
9赞 Jithin Shaji 6/4/2014 #13

如果使用单个字节来存储字符,则有 256 种可能的组合,因此您可以保存 256 个不同的字符。排序规则是定义字符以及比较和排序字符的规则的模式。

1252,即拉丁语1(ANSI),是最常见的。单字节字符集也不足以存储许多语言使用的所有字符。例如,某些亚洲语言有数千个字符,因此每个字符必须使用两个字节。

Unicode 标准

当在网络中使用使用多个代码页的系统时,管理通信变得困难。为了标准化,ISO 和 Unicode 联盟引入了 Unicode。Unicode 使用两个字节来存储每个字符。也就是说,可以定义 65,536 个不同的字符,因此几乎所有字符都可以用 Unicode 覆盖。如果两台计算机使用 Unicode,则每个符号都将以相同的方式表示,并且不需要转换 - 这就是 Unicode 背后的想法。

SQL Server 有两类字符数据类型:

  • 非 Unicode(char、varchar 和 text)
  • Unicode(nchar、nvarchar 和 ntext)

如果我们需要保存来自多个国家/地区的字符数据,请始终使用 Unicode。

9赞 Ali Elmi 2/16/2016 #14

虽然存储Unicode,但您应该考虑借助排序规则,也可以使用和保存本地语言的数据。NVARCHARVARCHAR

想象一下以下场景。

数据库的排序规则是波斯语,并且在数据类型中保存一个值,例如“علی”(阿里的波斯语写作)。没有问题,DBMS只使用三个字节来存储它。VARCHAR(10)

但是,如果要将数据传输到另一个数据库并查看正确的结果,则目标数据库必须具有与目标相同的排序规则,在本例中为波斯语。

如果目标排序规则不同,则会在目标数据库中看到一些问号 (?)。

最后,请记住,如果您使用的是用于本地语言的大型数据库,我建议您使用位置而不是使用太多空格。

我相信设计可以有所不同。这取决于您工作的环境。

8赞 Rafid 1/5/2017 #15

我看了一下答案,许多人似乎建议使用 over,因为空间不再是问题,因此启用 Unicode 以获得很少的额外存储空间并没有什么坏处。好吧,当您想在列上应用索引时,这并不总是正确的。SQL Server 对可编制索引的字段的大小限制为 900 个字节。因此,如果您有一个,您仍然可以索引它,但不能.使用 时,字符数减半,因此最多可以编制索引。因此,如果您确信自己不需要,我不建议使用它。nvarcharvarcharvarchar(900)varchar(901)nvarcharnvarchar(450)nvarchar

一般来说,在数据库中,我建议坚持使用您需要的大小,因为您始终可以扩展。例如,一位同事曾经认为,使用色谱柱没有坏处,因为我们的存储完全没有问题。后来,当我们尝试对此列应用索引时,SQL Server 拒绝了这一点。但是,如果他从 even 开始,我们可以简单地将其扩展到我们需要的内容,而不会出现这样的问题,这需要我们制定一个现场迁移计划来解决这个问题。nvarchar(max)varchar(5)

26赞 Debendra Dash 5/14/2017 #16

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

在此处输入图像描述

Varchar(可变长度、非 Unicode 字符数据)大小最大为 8000。

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

在此处输入图像描述

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

  1. 它是一种可变长度数据类型
  2. 用于存储 Unicode 字符。
  3. 数据以 Unicode 编码存储。每 支持语言。(例如阿拉伯语、德语、印地语等语言)
2赞 Rinoy Ashokan 8/10/2017 #17

nvarchar为了使我们的代码没有错误(类型不匹配),使用起来是安全的,因为也允许 Unicode 字符。 当我们在 SQL Server 查询中使用条件并且使用运算符时,它会多次抛出错误。可能的原因是我们的映射列将在 中定义。如果我们在这个问题中定义它,我不会发生。尽管如此,我们仍然坚持并避免这个问题,我们最好使用关键字而不是.varcharnvarcharwhere=varcharnvarcharvarcharLIKE=

评论

0赞 yolob 21 11/18/2020
like 和 = 之间的区别是对 varchar 和 nvarchar 的支持
7赞 Allan F 4/9/2019 #18

声誉评分为 ~47000 的 Jeffrey L Whitledge 建议使用 nvarchar

声誉得分为 ~33200 的 Solomon Rutzky 建议:不要总是使用 NVARCHAR。这是一种非常危险,而且往往代价高昂的态度/方法。

varchar 和 nvarchar SQL Server 数据类型之间的主要性能差异是什么?

https://www.sqlservercentral.com/articles/disk-is-cheap-orly-4

两人都有这么高的声誉,一个学习SQL Server数据库的开发人员会选择什么呢?

如果选择不一致,则在有关性能问题的答案和评论中会有许多警告。

有评论赞成/反对 nvarchar 的性能。

有评论赞成/反对 varchar 的性能。

我对包含数百列的表有特殊要求,这本身可能很不寻常?

我选择 varchar 是为了避免接近 SQL*server 2012 的 8060 字节表记录大小限制。

对我来说,使用 nvarchar 超出了这个 8060 字节的限制。

我还认为我应该将相关代码表的数据类型与主中心表的数据类型相匹配。

我曾看到,在南澳大利亚州政府这个工作地点,以前有经验的数据库开发人员使用了 varchar 列,其中表行数将达到数百万或更多(在这些非常大的表中,如果有的话,nvarchar 列很少),所以也许预期的数据行量成为这个决定的一部分。

22赞 Alexander Bartosh 10/5/2020 #19

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

因此,从现在开始,区别在于大小。

在转化为速度差异的数据库系统中。

更少的数据 = 更少的 IO + 更少的内存 = 更高的速度。阅读上面的文章了解数字。

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

仅当您的数据百分比很大,字符范围在 2048 - 16383 和 16384 – 65535 之间时,您才必须进行测量

评论

3赞 kamilk 3/29/2022
一个被严重低估的答案。我想知道有多少新数据库会使用 nvarchar,因为工程师只阅读了 2008 年的最佳答案。
1赞 ColdCat 10/18/2022
UTF8 有一些限制,您不能将该排序规则与 OLTP (SQLServer 2019) 一起使用,因此,如果MEMORY_OPTIMIZED表和过程NATIVE_COMPILATION是必需的,最好不要依赖 UTF8。
0赞 zu1b 4/14/2023
@kamilk,没有被低估,只是没那么有用。我们中的很多人都在处理不支持这种行为的旧 SQL 平台。其 2019 年及以上。此外,世界比你想象的要大。UT8 对于产品必须在国际上发挥作用的许多情况来说很小。IO 很便宜,因此 NVARCHAR 是更好的选择。
28赞 Amar Anondo 3/1/2021 #20

varchar仅用于另一方面,用于 和 字符。它们之间的其他一些区别如下。non-Unicode charactersnvarcharunicodenon-unicode

VARCHAR 与 NVARCHAR

瓦尔查尔 内瓦查尔
字符数据类型 可变长度、非 Unicode 字符 可变长度,Unicode 和非 Unicode 字符,如日语、朝鲜语和中文。
最大长度 为止8,000 characters 为止4,000 characters
字符大小 每个字符占用1 byte 占用每个 Unicode/非 Unicode 字符2 bytes
存储大小 实际长度(以字节为单位) 实际长度的 2 倍(以字节为单位)
用法 当数据长度为可变或可变长度列时使用,并且实际数据始终小于容量 由于仅存储,仅当需要 Unicode 支持(如日语汉字或朝鲜韩文字符)时才使用。
2赞 pavnis 7/21/2022 #21

varchar 适用于存储非 unicode,这意味着有限的字符。虽然 nvarchar 是 varchar 的超集,因此除了我们可以使用 varchar 存储哪些字符外,我们还可以在不忽略函数的情况下存储更多字符。

有人评论说,现在存储/空间不是问题。即使空间对一个人来说不是问题,确定最佳数据类型也应该是一个要求。

这不仅与存储有关!“数据移动”,你就会明白我想要去哪里!

0赞 Guillaume Simard 12/16/2023 #22

与此线程中的一些过时的答案相反,varchar 可以存储 Unicode 字符,如果您想使用 UTF-8,这也是您的不二之选。 解决方案是将数据库排序规则设置为Latin1_General_100_CI_AS_SC_UTF8

CREATE DATABASE [TestUTF-8] COLLATE Latin1_General_100_CI_AS_SC_UTF8
GO
USE [TestUTF-8]
GO

-- using varchar works
DECLARE @XML xml = '<?xml version="1.0" encoding="utf-8"?>
<test>
    <status>Success ✅</status>
</test>
'

-- using nvarchar will fail (XML parsing: line 1, character 38, unable to switch the encoding)
-- DECLARE @XML xml = N'<?xml version="1.0" encoding="utf-8"?>
-- <test>
--     <status>Success ✅</status>
-- </test>
-- '

SELECT [status] = c.c.value('(./status)[1]', 'varchar(max)') 
FROM @XML.nodes('/test') c(c)