我正在使用,在学校为小型Web应用程序开发数据库SQL Server 2005
。
我看到一些关于varchar
vs 问题的流派nvarchar
:
- 使用
varchar
除非你处理了很多国际化的数据,然后使用nvarchar
。 - 只需使用
nvarchar
一切。
我开始看到视图2的优点。我知道nvarchar确实占用了两倍的空间,但这并不一定是什么大问题,因为这只会存储数百名学生的数据。在我看来,最简单的方法就是不用担心,只允许所有内容都使用nvarchar。还是我想念的东西?
我正在使用,在学校为小型Web应用程序开发数据库SQL Server 2005
。
我看到一些关于varchar
vs 问题的流派nvarchar
:
varchar
除非你处理了很多国际化的数据,然后使用nvarchar
。nvarchar
一切。我开始看到视图2的优点。我知道nvarchar确实占用了两倍的空间,但这并不一定是什么大问题,因为这只会存储数百名学生的数据。在我看来,最简单的方法就是不用担心,只允许所有内容都使用nvarchar。还是我想念的东西?
Answers:
始终使用nvarchar。
对于大多数应用程序,您可能永远不需要双字节字符。但是,如果需要支持双字节语言,并且数据库模式中仅支持单字节,那么回头修改整个应用程序确实很昂贵。
将一个应用程序从varchar迁移到nvarchar的成本将比您在大多数应用程序中使用的额外磁盘空间少得多。
磁盘空间不是问题……但是内存和性能将成为问题。页面读取翻倍,索引大小翻倍,奇怪的LIKE和=恒定行为等
您需要存储中文等脚本吗?是还是不是...
并来自MS BOL“ Unicode的存储和性能影响 ”
编辑:
最近的SO问题强调了nvarchar性能可能有多差...
始终如一!将VARCHAR联接到NVARCHAR会对性能产生重大影响。
nvarchar
,varchar
转换nvarchar
为varchar
,再加入并没有明显的区别varchar
。当然,除非您的意思是列数据类型一致,而不是联接一致。
VARCHAR
和时看到性能急剧下降NVARCHAR
,那应该是由于该VARCHAR
列的索引以及用于该列的排序规则的类型(以及索引)所致。我在以下博客文章中详细介绍了此主题:混合VARCHAR和NVARCHAR类型时对索引的影响。
nvarchar的是要在内存,存储,工作组和索引显著的开销,因此,如果规范,决定了其真的会永远是必要的,不要打扰。
我不会有严格的“总是nvarchar”规则,因为它在许多情况下可能是完全浪费的-特别是来自ASCII / EBCDIC的ETL或通常是键和外键的标识符和代码列。
另一方面,在列的情况很多,我一定会提早问这个问题,如果我没有立即获得一个快速而准确的答案,我将列设为nvarchar。
我犹豫在这里添加另一个答案,因为已经有很多答案了,但是需要提出一些尚未提出或没有明确提出的观点。
第一:待办事项不经常使用NVARCHAR
。这是非常危险的,而且往往是昂贵的态度/方法。最好不要说“ 从不使用游标”,因为它们有时是解决特定问题的最有效方法,并且进行WHILE
循环的常见解决方案几乎总是比正确完成游标要慢。
建议您“始终做最适合情况的”时,才应使用“始终”一词。当然,这通常很难确定,尤其是在试图平衡开发时间的短期收益时(经理:“我们需要此功能-您直到一周前才知道的功能!”)长期维护成本(最初向团队施加压力,要求其在3周的冲刺中完成3个月的项目的经理:“我们为什么会遇到这些性能问题?我们怎么可能做没有灵活性的X?我们负担不起一两个冲刺即可解决此问题。我们一周之内可以完成什么工作,以便我们可以重新处理优先事项?我们绝对需要在设计上花费更多的时间,以免这种情况不断发生!”)
第二: @gbn的答案涉及一些非常重要的要点,当路径不是100%清晰时,在做出某些数据建模决策时要考虑。但是,还有更多需要考虑的问题:
浪费空间对整个系统具有巨大的级联效应。我写了一篇文章,详细介绍了该主题:磁盘便宜!奥利?(需要免费注册;抱歉,我无法控制该政策)。
第三:虽然有些答案错误地侧重于“这是一个小应用程序”方面,而有些答案正确地建议“使用适当的内容”,但这些答案都没有为OP提供真正的指导。问题中提到的重要细节这是他们学校的网页。大!因此,我们建议:
NVARCHAR
因为,随着时间的推移,它只是变得更可能是来自其他文化的名称将显示在那些地方了。VARCHAR
与适当的代码页一起使用(由字段的排序规则确定)。INT
/,TINYINT
因为ISO代码是固定长度的,易于阅读,而且是标准的:),请使用CHAR(2)
两个字母代码,CHAR(3)
如果使用3个字母代码。并考虑使用二进制排序规则,例如Latin1_General_100_BIN2
。VARCHAR
因为这是国际标准,切勿使用AZ以外的任何字母。是的,VARCHAR
即使仅存储美国邮政编码而不是INT ,也仍要使用,因为邮政编码不是数字,它们是字符串,并且其中一些带有前导“ 0”。并考虑使用二进制排序规则,例如Latin1_General_100_BIN2
。NVARCHAR
因为这两个现在都可以包含Unicode字符。第四:现在,您的NVARCHAR
数据占用的空间是正常存储的数据VARCHAR
(“正常存储” =不会变成“?”)所需空间的两倍,并且就像魔术一样,应用程序确实在增长现在至少在这些字段之一中有数百万条记录,其中大多数行是标准ASCII,但有些行包含Unicode字符,因此必须保留NVARCHAR
,请考虑以下几点:
如果您使用的是SQL Server 2008-2016 RTM 且在Enterprise Edition上,或者使用SQL Server 2016 SP1(使Data Compression在所有版本中均可用)或更高版本,则可以启用Data Compression。数据压缩可以(但不会“总是”)压缩NCHAR
and NVARCHAR
字段中的Unicode数据。决定因素是:
NCHAR(1 - 4000)
并NVARCHAR(1 - 4000)
使用Unicode的标准压缩方案,但只能在SQL Server 2008 R2中开始,并且仅对行数据有效,而不能用于过流!这似乎比常规的ROW / PAGE压缩算法要好。NVARCHAR(MAX)
并且XML
(而且我猜也是VARBINARY(MAX)
,TEXT
和NTEXT
)行内(不在LOB或OVERFLOW页中的行外)数据至少可以进行PAGE压缩,而不能进行 ROW压缩。当然,PAGE压缩取决于行内值的大小:我使用VARCHAR(MAX)进行了测试,发现不会压缩6000个字符/字节的行,但是会压缩4000个字符/字节的行。如果使用SQL Server 2005或2008-2016 RTM 而不在Enterprise Edition上使用,则可以有两个字段:一个VARCHAR
和一个NVARCHAR
。例如,假设您存储的URL大多都是基本ASCII字符(值0-127),因此适合VARCHAR
,但有时具有Unicode字符。您的架构可以包括以下3个字段:
...
URLa VARCHAR(2048) NULL,
URLu NVARCHAR(2048) NULL,
URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
AND ([URLa] IS NULL OR [URLu] IS NULL))
);
在此模型中,您只能从[URL]
计算列中进行选择。对于插入和更新,您可以通过查看转换是否会改变输入值来确定要使用哪个字段,该字段必须是以下NVARCHAR
类型:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
您可以将传入值GZIP VARBINARY(MAX)
压缩,然后在解压缩时解压缩:
COMPRESS
和DECOMPRESS
函数,它们也是GZip。如果使用SQL Server 2017或更高版本,则可以考虑使该表成为集群列存储索引。
虽然这不是一个可行的选择,但SQL Server 2019在VARCHAR
/ CHAR
数据类型中引入了对UTF-8的本机支持。当前有太多的错误需要使用,但是,如果它们已修复,则在某些情况下是一种选择。请参阅我的文章《SQL Server 2019中的本机UTF-8支持:救星还是假先知?》,以详细了解此新功能。
对于您的应用程序,nvarchar很好,因为数据库很小。说“总是使用nvarchar”是一个极大的简化。如果您不需要存储汉字或其他疯狂角色之类的东西,请使用VARCHAR,它将减少很多空间。我前任的前任在不需要时使用NVARCHAR设计了一些东西。我们最近将其切换为VARCHAR,仅在该表上保存了15 GB(已被高度写入)。此外,如果您在该表上有一个索引,并且想要包括该列或创建一个复合索引,则只需增加索引文件的大小即可。
请慎重考虑您的决定;在SQL开发和数据定义中,似乎很少有“默认答案”(当然,除了不惜一切代价避免使用游标)。
在过去的几年中,我们所有的项目都使用NVARCHAR进行所有操作,因为所有这些项目都是多语言的。从外部源(例如ASCII文件等)导入的数据在插入数据库之前先上转换为Unicode。
我还没有遇到较大的索引等与性能相关的问题。索引确实使用了更多的内存,但是内存很便宜。
无论您是使用存储过程还是动态构造SQL,请确保所有字符串常量都以N为前缀(例如SET @foo = N'Hello world。';),因此该常量也是Unicode。这样可以避免在运行时进行任何字符串类型转换。
YMMV。
为什么在所有讨论中都没有提到UTF-8?能够存储完整的unicode字符并不意味着必须始终为每个字符分配两个字节(或使用UNICODE术语的“代码点”)。所有ASCII均为UTF-8。SQL Server是否检查VARCHAR()字段以确保文本是严格的ASCII(即最高字节位为零)?我希望不会。
如果要存储unicode 并希望与旧的纯ASCII应用程序兼容,我认为使用VARCHAR()和UTF-8将是神奇的子弹:它仅在需要时使用更多空间。
对于那些不熟悉UTF-8的人,我建议使用底漆。
N
前缀类型)。您无法选择使用UTF-8。另外,Unicode编码(UTF-8,UCS-2 / UTF-16和UTF-32)不能应用于VARCHAR字段。