当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《varchar和nvarcharSQLServer数据类型之间的主要性能差异是什么?》经验,为你挑选了10个好方法。

我正在我的学校使用一个小型网络应用程序的数据库SQL Server 2005.
我在varcharvs 的问题上看到了几个思想流派nvarchar:

    使用varchar除非你处理了很多国际化的数据,然后使用nvarchar.

    只是nvarchar用于一切.

我开始看到视图2的优点.我知道nvarchar确实占用了两倍的空间,但这不一定是一个大问题,因为这只是为几百名学生存储数据.对我而言,似乎最简单的是不要担心它并且只允许一切使用nvarchar.还是有什么我想念的?



1> gbn..:

磁盘空间不是问题...但内存和性能将是.双页读取,双索引大小,奇怪的LIKE和=常量行为等

你需要存储中文等脚本吗?是还是不是...

从MS BOL" Unicode的存储和性能影响 "

编辑:

最近的SO问题突出了nvarchar性能有多糟糕......

在nvarchar字符串中搜索时,SQL Server使用高CPU


+1,如果你的应用程序走向国际,你会有许多其他问题需要担心搜索/替换nvarchar:多语言文本/消息,时区,计量单位和货币
@Qwertie:然后你使用nvarchar.你不做的是不必要地使用它.无论如何,这两个名字都适合varchar IIRC
说磁盘空间不是问题并不适合所有人.我们天真地在一个大型银行应用程序中不必要地使用nvarchar,并且多年来存储了数十亿条记录.凭借昂贵的基于SAN的存储以及复制,备份和灾难恢复,这实际上可以转化为nvarchar与varchar的数百万美元成本.更不用说每次读取都必须从磁盘读取两倍的字节,这会产生很大的(100%)性能影响.
但是,如果你需要存储一个外国名称,比如José或Bjørn呢?

2> Joe Barone..:

始终使用nvarchar.

对于大多数应用程序,您可能永远不需要双字节字符.但是,如果您需要支持双字节语言并且在数据库模式中只有单字节支持,那么在整个应用程序中返回和修改是非常昂贵的.

将一个应用程序从varchar迁移到nvarchar的成本远远超过您在大多数应用程序中使用的额外磁盘空间.


总是编码/规划一个多语言的网站(当你没有你需要它的时候)就像告诉所有年轻的成年人他们应该为他们的第一辆车购买一个8座大气,耗油量大的SUV ......毕竟他们可能有一天会结婚,可能会有6个孩子.我宁可享受性能和效率,也可以在需要的时候为升级付出代价.
索引大小,内存使用情况等怎么样?我假设你总是使用int当你也可以使用tinyint"以防万一"?
通常当人们用"总是"这个词开始回答时,你应该忽略之后发生的一切.(注意我用"通常"这个词开始说出来:)
回归并添加对多语言文本/消息,时区,度量单位和货币的支持要困难得多,所以每个人都必须从第一天开始在他们的应用程序中编码这些,总是(即使它只在你的主页上应用程序)!
如果使用.NET,添加对Unicode的支持并不困难.它可以像将varchar列更改为nvarchar一样简单,因为您不会丢失从代码页转换为Unicode的数据.现有的应用程序代码可能涉及您只需放松或删除的字符约束..NET字符数据已经是Unicode,并且SQL参数类型通常由数据库自动确定或隐式转换为列类型.SQL查询字符串常量可能需要以"N"为前缀,并且某些字符串编码调用可能需要使用UTF8或Unicode.
@cbmeeks:我*不*代码我*不知道.但是,如果你可以使用它而没有明显的性能损失,那么你的数据库不够大,无关紧要......
NVARCHAR是Unicode存储为UCS2,与仅使用普通VARCHAR相比,SQL Server使用2倍的存储空间.这意味着您可以在内存中缓存一半的行,并且您的存储IO需要两倍的时间.
这是一个可怕的可怕建议._Always_使用`NVARCHAR`?您不适用于EMC或Oracle,是吗?;-)
我知道这是旧的,但这是_bad建议_并且****不应该是接受的答案.

3> 小智..:

始终如一!JOIN-ING一个VARCHAR到NVARCHAR有一个很大的性能损失.


如果你正在对字符字段进行连接,那么你的数据库可能比使用nvarchar或varchar更糟糕,一般来说.

4> Cade Roux..:

nvarchar将在内存,存储,工作集和索引方面产生巨大的开销,因此如果规范规定它确实永远不会是必要的,那就不要打扰了.

我不会有一个坚硬而快速的"永远nvarchar"规则,因为在许多情况下它可能是完全浪费 - 特别是来自ASCII/EBCDIC的ETL或通常是键和外键的标识符和代码列.

另一方面,有很多列的情况,我肯定会提前问这个问题,如果我没有立即得到一个快速的答案,我会把列设为nvarchar.



5> Solomon Rutz..:

我不愿在这里添加另一个答案,因为已经有很多,但需要做出一些尚未制作或未制作清楚的要点.

第一:不要经常使用NVARCHAR.这是一种非常危险且往往代价高昂的态度/态度.并且最好说" 永远不要使用游标",因为它们有时是解决特定问题的最有效方法,并且执行WHILE循环的常见解决方法几乎总是比正确完成的游标慢.

你唯一应该使用"永远"这个词的时候就是建议"总是做最适合这种情况的事情".当然,这通常很难确定,特别是当试图平衡开发时间的短期收益时(经理:"我们需要这个功能 - 你直到现在才知道 - 一周前!")期限维护成本(经理最初迫使团队在为期3周的冲刺中完成为期3个月的项目:"为什么我们遇到这些性能问题?我们怎么可能做到没有灵活性的X?我们负担不起一两个冲刺来解决这个问题.我们可以在一周内完成什么工作,以便我们可以回到我们的优先项目?我们肯定需要在设计上花更多的时间,所以这不会继续发生!").

第二: @ gbn的答案涉及在路径不是100%明确时做出某些数据建模决策时要考虑的一些非常重要的要点.但还有更多要考虑的因素:

事务日志文件的大小

复制所需的时间(如果使用复制)

ETL所需的时间(如果是ETL)

将日志发送到远程系统并恢复所需的时间(如果使用日志传送)

备份大小

完成备份所需的时间长度

恢复所需的时间长度(这可能在某一天很重要;-)

tempdb所需的大小

触发器的性能(对于存储在tempdb中的inserted和deleted表)

行版本控制的性能(如果使用SNAPSHOT ISOLATION,因为版本存储在tempdb中)

当CFO表示他们去年在SAN上花费了100万美元时,他们不会再获得25万美元的额外存储空间,从而获得新磁盘空间的能力

执行INSERT和UPDATE操作所需的时间长度

索引维护所需的时间长度

等等等

浪费空间对整个系统产生巨大的级联效应.我写了一篇关于这个主题的明确细节的文章:磁盘便宜!ORLY?(需要免费注册;抱歉,我不控制该政策).

第三:虽然有些答案错误地关注"这是一个小应用程序"方面,有些正确建议"使用适当的",但没有一个答案为OP提供了真正的指导.问题中提到的一个重要细节这是他们学校的网页.大!所以我们可以建议:

学生和/或学院名称的字段可能应该是NVARCHAR因为,随着时间的推移,其他文化的名称越来越有可能出现在这些地方.

但对于街道地址和城市名称?该应用程序的目的没有说明(它会有所帮助),但假设地址记录(如果有的话)仅适用于特定地理区域(即单一语言/文化),则使用VARCHAR相应的代码页(其中是从字段的整理确定的).

如果存储状态和/或国家ISO代码(不需要存储INT/ TINYINT因为ISO代码是固定长度,人类可读,并且很好,标准:) CHAR(2)用于两个字母代码和CHAR(3)使用3个字母代码.并考虑使用二进制校对,如Latin1_General_100_BIN2.

如果存储邮政编码(即邮政编码),请使用,VARCHAR因为从不使用AZ以外的任何字母是国际标准.是的,VARCHAR即使只存储美国邮政编码而不是INT ,仍然使用,因为邮政编码不是数字,它们是字符串,其中一些有一个前导"0".并考虑使用二进制校对,如Latin1_General_100_BIN2.

如果存储电子邮件地址和/或URL,请使用,NVARCHAR因为这两者现在都可以包含Unicode字符.

等等....

第四:现在您的NVARCHAR数据占用的空间是其所需数据的两倍,而且数据非常适合VARCHAR("很好地适应"=不会变成"?")并且不知何故,好像通过魔术,应用程序确实增长了现在,至少有一个这样的字段中有数百万条记录,其中大多数行是标准ASCII,但有些包含Unicode字符,所以你必须保留NVARCHAR,请考虑以下内容:

    如果您使用的是SQL Server 2008 - 2016 RTM 在Enterprise Edition上,或者如果使用SQL Server 2016 SP1(在所有版本中都提供了数据压缩)或更新版本,则可以启用数据压缩.数据压缩可以(但不会"永远")在压缩Unicode数据NCHARNVARCHAR领域.决定因素是:

      NCHAR(1 - 4000)NVARCHAR(1 - 4000)使用Unicode的标准压缩方案,但仅从SQL Server 2008 R2开始,并且只针对IN ROW数据,而不是OVERFLOW!这似乎比常规的ROW/PAGE压缩算法更好.

      NVARCHAR(MAX)XML(我想也是VARBINARY(MAX),TEXTNTEXT)IN IN的数据(不是LOB或OVERFLOW页面中的行)可以至少进行PAGE压缩,但不能进行 ROW压缩.当然,PAGE压缩取决于行内值的大小:我用VARCHAR(MAX)测试并看到6000个字符/字节行不会压缩,但是4000个字符/字节行.

      任何OFF ROW数据,LOB或OVERLOW =没有您的压缩!

    如果使用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]计算列中进行SELECT .对于插入和更新,您可以通过查看转换是否更改传入值来确定要使用的字段,传入值必须是以下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),然后在解决方法中解压缩:

    对于SQL Server 2005 - 2014:您可以使用SQLCLR.SQL#(我写的一个SQLCLR库)附带免费版的Util_GZipUtil_GUnzip

    对于SQL Server 2016及更高版本:您可以使用内置COMPRESSDECOMPRESS函数,它们也是GZip.

    如果使用SQL Server 2017或更高版本,则可以考虑将表格设置为Clustered Columnstore Index.

    虽然这还不是一个可行的选择,但SQL Server 2019在VARCHAR/ CHARdatatypes中引入了UTF-8的原生支持.目前有太多的bug用于它,但如果它们被修复,那么这是一些场景的选项.请参阅我的帖子," SQL Server 2019中的原生UTF-8支持:救世主还是假先知? ",详细分析了这一新功能.


**慢速拍手.**令人惊讶的是,"总是使用nvarchar"得到了140票,但事实并非如此.这篇文章很棒.

6> WebMasterP..:

对于您的应用程序,nvarchar很好,因为数据库大小很小.说"总是使用nvarchar"是一个巨大的过度简化.如果你不需要存储像汉字或其他疯狂字符这样的东西,使用VARCHAR,它将使用更少的空间.我的前任在我目前的工作中使用NVARCHAR设计了一些不需要的东西.我们最近将它切换到VARCHAR并在该表上保存了15 GB(它被高度写入).此外,如果您在该表上有索引并且想要包含该列或创建复合索引,那么您只需将索引文件大小设置得更大.

只要在你的决定中考虑周全; 在SQL开发和数据定义中,似乎很少有"默认答案"(当然,除了不惜一切代价避免使用游标).



7> tbreffni..:

由于您的应用程序很小,使用nvarchar而不是varchar基本上没有明显的成本增加,如果您需要存储unicode数据,您可以节省潜在的麻烦.



8> Kjetil Klaus..:

一般来说; 从具有最少约束的最昂贵数据类型开始.把它投入生产.如果性能开始成为问题,请找出实际存储在这些nvarchar列中的内容.那里有不适合的角色varchar吗?如果没有,请切换到varchar.在您知道疼痛的位置之前,不要尝试进行预先优化.我的猜测是nvarchar/varchar之间的选择并不会在可预见的未来减缓你的应用程序.将有应用程序的其他部分,其中性能调优会给你更多的钱爆炸.



9> devstuff..:

在过去的几年里,我们所有的项目都使用了NVARCHAR,因为所有这些项目都是多语言的.从外部源导入的数据(例如ASCII文件等)在插入数据库之前上转换为Unicode.

我还没有遇到来自较大索引等的任何与性能相关的问题.索引确实使用了更多内存,但内存很便宜.

不管你使用存储过程或随时构建SQL确保所有字符串常量都用N前缀(如SET @foo = N'Hello世界.)所以常数也统一.这避免了运行时的任何字符串类型转换.

因人而异.


您正在使用的表中可能没有几亿条记录.我同意,对于大多数默认为nvarchar的应用程序都很好,但不是全部.

10> 小智..:

我可以从中获得经验,谨防nvarchar.除非您绝对需要,否则此数据字段类型会破坏较大数据库的性能.我继承了一个在性能和空间方面受到损害的数据库.我们能够将30GB的数据库大小减少70%!还有一些其他的改进来帮助提高性能,但我确信这varchar也有很大的帮助.如果您的数据库有可能将表增长到一百万+记录,那就nvarchar不惜一切代价.

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有