【问题标题】:Are there any disadvantages to always using nvarchar(MAX)?总是使用 nvarchar(MAX) 有什么缺点吗?
【发布时间】:2010-09-13 23:40:38
【问题描述】:

在 SQL Server 2005 中,将所有字符字段设为 nvarchar(MAX) 而不是显式指定长度是否有任何缺点,例如nvarchar(255)? (除了你无法在数据库级别限制字段长度这一显而易见的问题)

【问题讨论】:

  • 我只是不明白你为什么要让某人输入超过 8000 个字符的名称。
  • 同样的逻辑可以应用于编程语言。为什么不为我们所有的数据返回旧的 VB6 变体?我认为在多个地方进行制衡并不一定是坏事。
  • 您的更新应该是对这个问题的答案。
  • answer-in-question 移至正确答案,因为原作者没有这样做。 stackoverflow.com/a/35177895/10245 我觉得 7 年足够了 :-)

标签: sql sql-server sql-server-2005


【解决方案1】:

我发现的唯一问题是我们在 SQL Server 2005 上开发应用程序,在一个实例中,我们必须支持 SQL Server 2000。我刚刚了解到,SQL Server 2000 的困难方式不喜欢 varchar 或 nvarchar 的 MAX 选项。

【讨论】:

  • 那么为什么不只在最小的公分母上开发呢?
【解决方案2】:

这是一个公平的问题,而且他确实除了显而易见的问题之外……

缺点可能包括:

性能影响 查询优化器使用字段大小来确定最有效的执行计划

"1.数据库的extends和pages的空间分配是灵活的。因此当使用update向字段添加信息时,如果新数据比之前插入的数据长,您的数据库将不得不创建一个指针。这就是数据库文件会变得碎片化 = 几乎所有方面的性能都会降低,从索引到删除、更新和插入。” http://sqlblogcasts.com/blogs/simons/archive/2006/02/28/Why-use-anything-but-varchar_2800_max_2900_.aspx

集成影响 - 其他系统很难知道如何与您的数据库集成 不可预测的数据增长 可能的安全问题,例如你可能会因为占用所有磁盘空间而导致系统崩溃

这里有一篇好文章: http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1098157,00.html

【讨论】:

  • +1 用于集成和安全隐患。当大多数其他答案谈论性能时,这些是要考虑的原始角度。如果所有列都是varchar(max),则任何使用元数据提供合理默认控件大小的工具(例如报表编写器或表单设计器)都需要更多的工作才能使用。
  • 数据库集成是我所知道的最荒谬的事情。如果只是导入一次,您可以通过 LEN 功能检查之前的数据。
【解决方案3】:

在 MSDN 论坛上提出了同样的问题:

来自原始帖子(那里有更多信息):

当您将数据存储到 VARCHAR(N) 列时,这些值的物理存储方式相同。但是,当您将其存储到 VARCHAR(MAX) 列时,屏幕后面的数据将作为 TEXT 值处理。所以在处理 VARCHAR(MAX) 值时需要一些额外的处理。 (仅当大小超过 8000 时)

VARCHAR(MAX) 或 NVARCHAR(MAX) 被视为“大值类型”。大值类型通常存储在“行外”。这意味着数据行将有一个指向另一个存储“大值”的位置的指针......

【讨论】:

  • 那么问题应该是,使用 N/VARCHAR(MAX) 和 N/TEXT 有区别吗?
  • 如果我没记错的话,它们不是只有在大小超过 8k 时才存储在行外吗?
  • 我将答案读作“不,使用N/VARCHAR(MAX) 没有任何缺点”,因为“仅当大小超过 8000”时才会有额外的处理。因此,您仅在必要时才会产生成本,并且您的数据库限制较少。我读错了吗?似乎您几乎总是想要N/VARCHAR(MAX) 而不是N/VARCHAR(1-8000)...
  • 上面的死链接 - MSDN 上问题的工作链接是 social.msdn.microsoft.com/Forums/en-US/sqlgetstarted/thread/…
  • 不幸的是,这个答案有很多问题。它使 8k 边界看起来像一个神奇的数字,这是不正确的,基于可能更多的因素,包括sp_tableoptionsmsdn.microsoft.com/en-us/library/ms173530.aspx,值被推出行。 VARCHAR(255) 类型也可以从行中推出,提到的“开销”对于 MAX 和 255 可能完全相同。它将 MAX 类型与 TEXT 类型进行比较,当它们不同时(操作完全不同的 API,不同的存储等)。它没有提到实际的区别:没有索引,没有对 MAX 类型的在线操作
【解决方案4】:

我有一个 udf,它填充了字符串并将输出放入 varchar(max)。如果直接使用它而不是回滚到正在调整的列的适当大小,则性能非常差。我最终将 udf 设置为带有大注释的任意长度,而不是依赖 udf 的所有调用者将字符串重新转换为更小的大小。

【讨论】:

    【解决方案5】:

    这将导致性能问题,尽管如果您的数据库很小,它可能永远不会导致任何实际问题。如果您一次搜索大量记录,每条记录将占用硬盘驱动器上的更多空间,并且数据库将需要读取磁盘的更多扇区。例如,一个小记录可以容纳 50 个扇区,而大记录可以容纳 5 个扇区。您需要使用大记录从磁盘读取 10 倍的数据。

    【讨论】:

    • -1。存储在 nvarchar(max) 列中的长度为 100 的字符串占用的磁盘空间不会比存储在 nvarchar(100) 列中的更多。
    • 如果存储数据的大小更大,您所描述的内容是正确的,但这个问题是关于数据类型是否具有性能影响或其他考虑因素。
    【解决方案6】:

    这将使屏幕设计更加困难,因为您将无法预测控件的宽度。

    【讨论】:

      【解决方案7】:

      有趣的链接:Why use a VARCHAR when you can use TEXT?

      这是关于 PostgreSQL 和 MySQL 的,所以性能分析是不同的,但“显性”的逻辑仍然成立:为什么要强迫自己总是担心一小部分时间相关的事情?如果您将电子邮件地址保存到变量中,您将使用“字符串”而不是“限制为 80 个字符的字符串”。

      【讨论】:

      • 这类似于争辩说你不应该有检查约束来确保一个人的年龄不是负数。
      • 我看到了数据正确性和性能优化之间的区别。
      【解决方案8】:

      一个问题是,如果您必须使用多个版本的 SQL Server,MAX 并不总是有效。因此,如果您使用的是遗留数据库或任何其他涉及多个版本的情况,您最好非常小心。

      【讨论】:

      • 我认为 OP 的潜意识假设是他完全在处理 2005 多个实例,并且他的应用程序不需要在 2000(或 ack,更低)版本上运行.不过,如果需要支持旧版本,我完全同意你的看法!
      • John Rudy:我想是这样的,我只知道我自己也遇到了这些障碍,而我并不认为自己会这样做。
      • 实际上,由于 SQL CE 4 不支持 MAX 列类型,因此现代东西仍然存在这个普遍问题,因此互操作性很麻烦。
      【解决方案9】:

      有时您希望数据类型对其中的数据强制执行某种意义。

      例如,假设您有一列确实不应该超过 20 个字符。如果您将该列定义为 VARCHAR(MAX),则某些流氓应用程序可能会在其中插入一个长字符串,而您永远不会知道,或者有任何方法可以阻止它。

      下次您的应用程序使用该字符串时,假设该字符串的长度对于它所代表的域而言是适度且合理的,您将遇到不可预测且令人困惑的结果。

      【讨论】:

      • 我同意这一点,也同意其他一些 cmets,但我仍然认为这是业务层的责任。当它到达数据库层时,它应该打个招呼并存储值,不管它有多长。我认为这里真正起作用的是我认为大约 90% 的时间当开发人员指定 varchar(255) 时,他的意图并不是真正的 255 个字符,而是一些未指定的中等长度值。考虑到我的数据库中不合理的大值和不可预见的异常之间的权衡,我将采用大值。
      • 如果他们指定 VARCHAR(255) 来表示一些未知的长度,那么这是他们没有正确研究他们正在设计的内容的错。解决方案是让开发人员做好自己的工作,而不是让数据库允许不合理的值。
      • 对作者没有帮助。他明确排除了你给出答案的这个问题。
      • @Chris B Behrens:我不同意;数据库架构业务逻辑的一部分。表、关系、字段和数据类型的选择都是业务逻辑 - 值得使用 RDBMS 来强制执行此业务逻辑的规则。出于一个原因,很少有只有一个应用程序层访问数据库;例如,您可能有绕过主要业务层的数据导入和提取工具,这意味着您确实需要数据库来执行规则。
      • 如果您不需要或确实希望存储长字符串,那么最好对数据强制执行。例如,如果存储一个 PostCode 字段,您是否允许某人输入数百或数千个字符,而它应该是最多 10 个字符?- 最大大小应该在所有级别、客户端、业务层和数据库中进行验证。如果使用 C# 和实体框架等模型优先方法,您可以在模型中定义 maxsize 并将其应用于数据库、业务逻辑和客户端验证(使用 jquery 验证之类的)。仅在确实需要时才使用 nvarchar(max)
      【解决方案10】:

      当您知道该字段将在一个设定范围内时(例如 5 到 10 个字符),这是个坏主意。如果我不确定长度是多少,我想我只会使用 max 。例如,电话号码永远不会超过一定数量的字符。

      您能否坦率地说,您对表中每个字段的大致长度要求不确定吗?

      我确实明白你的意思——有些字段我当然会考虑使用 varchar(max)。

      有趣的是,MSDN docs 总结得很好:

      当 列数据条目差异很大。 使用 varchar(max) 当 列数据条目差异很大, 并且大小可能超过 8,000 字节。

      an interesting discussion on the issue here

      【讨论】:

      • 对于电话号码之类的东西,我更愿意使用 char 字段而不是 varchar。只要您在存储中保持标准并且不必担心来自不同国家/地区的电话号码,就永远不需要变量字段来存储电话号码(10 没有任何格式)或邮政编码(5或 9-10,如果添加最后四位数字)等。
      • 我指的是长度不同的电话号码。也许我应该把这个放在答案中。任何固定长度的东西我都会使用 char 字段。
      • 或者我应该在我的评论中说 nchar 或 char。 :-)
      • 电话号码中的字符数几乎是业务需求。如果您需要将国际标准代码与号码一起存储,则可能超过 10 个。或者,世界某些地方的电话号码可能超过 10 个数字。想象一下 IPV4 到 IPV6 过渡的情况。没有人会争辩说,在过去的 IPV4 时代,我们需要超过 12 位数字。如果 IPV6 变得流行起来,它可能不会保持良好状态。这又是一段时间内的业务规则更改。正如人们所说,变化是我们可以期待的唯一不变的事情:)
      • 小心假设您知道电话号码字段中可以包含多少个字符,或者它们将是什么类型的字符。除非系统使用该数据实际拨出(在这种情况下,您必须严格控制格式),否则用户可能会合法地将意外长字符串放在那里,例如“0123 456 78910 向前台请求分机 45,然后转接给 James”。
      【解决方案11】:

      将其视为另一个安全级别。您可以设计没有外键关系的表 - 完全有效 - 并确保完全在业务层上存在关联实体。但是,外键被认为是良好的设计实践,因为它们添加了另一个约束级别,以防业务层出现问题。字段大小限制和不使用 varchar MAX 也是如此。

      【讨论】:

        【解决方案12】:

        旧系统支持。如果您有一个正在使用数据的系统,并且预计它有一定的长度,那么数据库是强制执行该长度的好地方。这并不理想,但遗留系统有时并不理想。 =P

        【讨论】:

          【解决方案13】:

          如果一行中的所有数据(对于所有列)永远不会合理地占用 8000 或更少的字符,那么数据层的设计应该强制执行这一点。

          数据库引擎效率更高,可以将所有内容都排除在 Blob 存储之外。限制行越小越好。您可以在页面中塞入的行越多越好。当需要访问更少的页面时,数据库的性能会更好。

          【讨论】:

            【解决方案14】:

            不使用 max 或 text 字段的一个原因是您无法执行 online index rebuilds 即 REBUILD WITH ONLINE= ON 即使使用 SQL Server Enterprise Edition。

            【讨论】:

            • TEXT 字段类型也存在同样的限制,因此您仍应使用 VARCHAR(MAX) 而不是 TEXT。
            • 因此我们无法重建聚集索引。在我们将列提取到它自己的表中之前,它花费了我们很多磁盘空间(我们不能将表锁定超过 7 秒)
            【解决方案15】:

            数据库的工作是存储数据,以供企业使用。使这些数据有用的一部分是确保它是有意义的。允许某人为他们的名字输入无限数量的字符并不能确保有意义的数据。

            将这些约束构建到业务层是一个好主意,但这并不能确保数据库保持完整。保证不违反数据规则的唯一方法是在数据库中尽可能低的级别强制执行它们。

            【讨论】:

            • IMO,数据长度限制纯粹基于业务规则,随着应用程序的增长,可能会在一段时间内发生变化。在业务逻辑上更改业务规则比在数据库级别更容易。所以,我认为数据库应该足够灵活,不应该与业务规则绑定,例如名字的最大允许长度,这在很大程度上取决于你的用户所在的世界。
            【解决方案16】:

            我能看到的主要缺点是假设你有这个:

            哪一项为您提供了有关 UI 所需数据的最多信息?

            这个

                        CREATE TABLE [dbo].[BusData](
                            [ID] [int] IDENTITY(1,1) NOT NULL,
                            [RecordId] [nvarchar](MAX) NULL,
                            [CompanyName] [nvarchar](MAX) NOT NULL,
                            [FirstName] [nvarchar](MAX) NOT NULL,
                            [LastName] [nvarchar](MAX) NOT NULL,
                            [ADDRESS] [nvarchar](MAX) NOT NULL,
                            [CITY] [nvarchar](MAX) NOT NULL,
                            [County] [nvarchar](MAX) NOT NULL,
                            [STATE] [nvarchar](MAX) NOT NULL,
                            [ZIP] [nvarchar](MAX) NOT NULL,
                            [PHONE] [nvarchar](MAX) NOT NULL,
                            [COUNTRY] [nvarchar](MAX) NOT NULL,
                            [NPA] [nvarchar](MAX) NULL,
                            [NXX] [nvarchar](MAX) NULL,
                            [XXXX] [nvarchar](MAX) NULL,
                            [CurrentRecord] [nvarchar](MAX) NULL,
                            [TotalCount] [nvarchar](MAX) NULL,
                            [Status] [int] NOT NULL,
                            [ChangeDate] [datetime] NOT NULL
                        ) ON [PRIMARY]
            

            还是这个?

                        CREATE TABLE [dbo].[BusData](
                            [ID] [int] IDENTITY(1,1) NOT NULL,
                            [RecordId] [nvarchar](50) NULL,
                            [CompanyName] [nvarchar](50) NOT NULL,
                            [FirstName] [nvarchar](50) NOT NULL,
                            [LastName] [nvarchar](50) NOT NULL,
                            [ADDRESS] [nvarchar](50) NOT NULL,
                            [CITY] [nvarchar](50) NOT NULL,
                            [County] [nvarchar](50) NOT NULL,
                            [STATE] [nvarchar](2) NOT NULL,
                            [ZIP] [nvarchar](16) NOT NULL,
                            [PHONE] [nvarchar](18) NOT NULL,
                            [COUNTRY] [nvarchar](50) NOT NULL,
                            [NPA] [nvarchar](3) NULL,
                            [NXX] [nvarchar](3) NULL,
                            [XXXX] [nvarchar](4) NULL,
                            [CurrentRecord] [nvarchar](50) NULL,
                            [TotalCount] [nvarchar](50) NULL,
                            [Status] [int] NOT NULL,
                            [ChangeDate] [datetime] NOT NULL
                        ) ON [PRIMARY]
            

            【讨论】:

            • 我希望业务逻辑告诉我公司名称最多可以包含 50 个字符,而不是依赖数据库表来获取该信息。
            • 我同意杰夫的观点。我认为持久存储不是定义业务规则的正确位置。在分层架构中,您的 UI 甚至都不知道持久层。
            • 当然,除非您使用的是限制为特定大小的值,例如国家/地区的 ISO 代码。
            • 这与表定义有什么关系?您仍然可以拥有业务逻辑。我认为您的观点与表格的设计方式无关。如果您仍想在业务层中设计某种定义,那就这样吧。尽管更有意义的是,无论如何在业务层中使用存储过程;不是表定义??
            • 这似乎不受欢迎,但我同意 carlos 的观点,如果 db 设置了最大大小,那么您可以对在它之上构建的所有层感到满意,您可能需要处理这些层。如果您有多个系统写入数据库,这一点尤其重要。
            【解决方案17】:

            一个缺点是您将围绕一个不可预测的变量进行设计,并且您可能会忽略而不是利用内部 SQL Server 数据结构,该结构逐渐由 Row(s)、Page(s) 和 Extent( s)。

            这让我想到了 C 语言中的 data structure alignment,并且意识到对齐通常被认为是一件好事 (TM)。相似的想法,不同的背景。

            Pages and Extents 的 MSDN 页面

            Row-Overflow Data 的 MSDN 页面

            【讨论】:

              【解决方案18】:

              1) SQL 服务器在处理 nvarchar(max) 与 nvarchar(n) 时必须使用更多资源(分配的内存和 cpu 时间),其中 n 是特定于字段的数字。

              2) 这对性能意味着什么?

              在 SQL Server 2005 上,我从具有 15 个 nvarchar(max) 列的表中查询了 13,000 行数据。 我反复对查询进行计时,然后将列更改为 nvarchar(255) 或更少。

              优化前的查询平均为 2.0858 秒。更改后的查询平均在 1.90 秒内返回。这比基本的 select * 查询改进了大约 184 毫秒。那是 8.8% 的改进。

              3) 我的结果与其他几篇表明存在性能差异的文章一致。根据您的数据库和查询,改进的百分比可能会有所不同。如果您没有很多并发用户或很多记录,那么性能差异对您来说不是问题。但是,随着更多记录和并发用户的增加,性能差异会增加。

              【讨论】:

                【解决方案19】:

                我查看了一些文章并从中找到了有用的测试脚本:http://www.sqlservercentral.com/Forums/Topic1480639-1292-1.aspx 然后将其更改为在 NVARCHAR(10) 与 NVARCHAR(4000) 与 NVARCHAR(MAX) 之间进行比较,并且在使用指定数字但使用 MAX 时我没有发现速度差异。你可以自己测试。希望对您有所帮助。

                SET NOCOUNT ON;
                
                --===== Test Variable Assignment 1,000,000 times using NVARCHAR(10)
                DECLARE @SomeString NVARCHAR(10),
                        @StartTime DATETIME;
                --=====         
                 SELECT @startTime = GETDATE();
                 SELECT TOP 1000000
                        @SomeString = 'ABC'
                   FROM master.sys.all_columns ac1,
                        master.sys.all_columns ac2;
                 SELECT testTime='10', Duration = DATEDIFF(ms,@StartTime,GETDATE());
                GO
                --===== Test Variable Assignment 1,000,000 times using NVARCHAR(4000)
                DECLARE @SomeString NVARCHAR(4000),
                        @StartTime DATETIME;
                 SELECT @startTime = GETDATE();
                 SELECT TOP 1000000
                        @SomeString = 'ABC'
                   FROM master.sys.all_columns ac1,
                        master.sys.all_columns ac2;
                 SELECT testTime='4000', Duration = DATEDIFF(ms,@StartTime,GETDATE());
                GO
                --===== Test Variable Assignment 1,000,000 times using NVARCHAR(MAX)
                DECLARE @SomeString NVARCHAR(MAX),
                        @StartTime DATETIME;
                 SELECT @startTime = GETDATE();
                 SELECT TOP 1000000
                        @SomeString = 'ABC'
                   FROM master.sys.all_columns ac1,
                        master.sys.all_columns ac2;
                 SELECT testTime='MAX', Duration = DATEDIFF(ms,@StartTime,GETDATE());
                GO
                

                【讨论】:

                • 这很有趣。在我的盒子上,MAX 的速度似乎慢了 4 倍。
                • SQL Server 2012 上的新结果:10 比 4k 慢两倍,MAX 比 4k 慢 5.5 倍。
                • 大部分时间是从 varchar 到 nvarchar(max) 的隐式转换。试试这个:DECLARE \@SomeString NVARCHAR(MAX), \@abc NVARCHAR(max) = N'ABC', \@StartTime DATETIME;选择 @startTime = GETDATE(); SELECT TOP 1000000 \@SomeString = \@abc FROM master.sys.all_columns ac1, master.sys.all_columns ac2; SELECT testTime='MAX', 持续时间 = DATEDIFF(ms,\@StartTime,GETDATE());必须在变量之前插入 \ 才能发布。
                • SSD 上的 SQL Server 2014:150、156、716(10、4000、MAX)。
                • 感谢您在本次讨论中添加一些实数。我们经常忘记构建测试用例是获得洞察力的最快方法。
                【解决方案20】:

                根据接受的答案中提供的链接,看来:

                1. nvarchar(MAX) 字段中存储的 100 个字符与nvarchar(100) 字段中存储的 100 个字符没有什么不同 - 数据将内联存储,您不会有读取和写入数据的开销行'。所以那里不用担心。

                2. 如果大小大于 4000,数据将自动“行外”存储,这正是您想要的。所以也不用担心。

                不过……

                1. 您不能在nvarchar(MAX) 列上创建索引。您可以使用全文索引,但不能在列上创建索引来提高查询性能。对我来说,这就是一笔交易……总是使用 nvarchar(MAX) 是一个明显的劣势。

                结论:

                如果你想要一种贯穿整个数据库的“通用字符串长度”,它可以被索引并且不会浪费空间和访问时间,那么你可以使用nvarchar(4000)

                【讨论】:

                • 仅供参考,这是添加到原始问题的编辑,应该作为答案发布
                • 谢谢,对我来说这是最终答案。我问过自己同样的问题 - 为什么不一直使用 nvarchar(max) - 就像 C# 中的 string 一样? - 但第 3 点)(索引问题)给出了答案。
                • 添加了一个编辑。作为一种“通用字符串长度”,您始终可以使用nvarchar(4000)
                • @SQLGeorge 请参阅Martin Smith 的出色回答,了解声明比以往更宽的列对查询性能的影响
                • @billinkc 谢谢,这是一篇很棒的文章。好的,所以尺寸确实会影响性能。我将再次编辑答案。
                【解决方案21】:

                如上所述,它主要是存储和性能之间的权衡。至少在大多数情况下。

                但是,在选择 n/varchar(Max) 而不是 n/varchar(n) 时,至少还应考虑一个其他因素。数据是否会被索引(例如,姓氏)?由于 MAX 定义被视为 LOB,因此任何定义为 MAX 的内容都不可用于索引。如果没有索引,任何在 WHERE 子句中将数据作为谓词的查找都将被强制进行全表扫描,这是数据查找所能获得的最差性能。

                【讨论】:

                  【解决方案22】:

                  我的测试表明,选择时存在差异。

                  CREATE TABLE t4000 (a NVARCHAR(4000) NULL);
                  
                  CREATE TABLE tmax (a NVARCHAR(MAX) NULL);
                  
                  DECLARE @abc4 NVARCHAR(4000) = N'ABC';
                  
                  INSERT INTO t4000
                  SELECT TOP 1000000 @abc4
                      FROM
                      master.sys.all_columns ac1,
                      master.sys.all_columns ac2;
                  
                  DECLARE @abc NVARCHAR(MAX) = N'ABC';
                  
                  INSERT INTO tmax
                  SELECT TOP 1000000 @abc
                      FROM
                      master.sys.all_columns ac1,
                      master.sys.all_columns ac2;
                  
                  SET STATISTICS TIME ON;
                  SET STATISTICS IO ON;
                  
                  SELECT * FROM dbo.t4000;
                  SELECT * FROM dbo.tmax;
                  

                  【讨论】:

                    【解决方案23】:

                    首先我想到了这个,但后来又想到了。存在性能影响,但同样它确实可以作为一种文档形式来了解字段的实际大小。当该数据库位于更大的生态系统中时,它确实会强制执行。在我看来,关键是要宽容,但仅限于合理范围内。

                    好的,这只是我对业务和数据层逻辑问题的感受。这取决于,如果您的数据库是共享业务逻辑的系统之间的共享资源,那么当然它似乎是执行此类逻辑的自然场所,但它不是最好的方法,最好的方法是提供 API,这允许要测试的交互并将业务逻辑保持在它所属的位置,它保持系统解耦,它保持系统内的层解耦。但是,如果您的数据库应该只为一个应用程序提供服务,那么让我们思考一下 AGILE,现在是真的吗?暂时设计。如果需要此类访问,请为该数据提供 API。

                    但显然,这只是理想情况,如果您使用现有系统,则很可能至少在短期内需要以不同的方式进行操作。

                    【讨论】:

                      【解决方案24】:

                      从 SQL Server 2019 开始,NVARCHAR(MAX)仍然不支持 SCSU“Unicode 压缩” - 即使使用行内数据存储进行存储。 SCSU 是在 SQL Server 2008 中添加的,适用于任何 ROW/PAGE 压缩表和索引。

                      因此,NVARCHAR(MAX) 与具有相同文本内容的 NVARCHAR(1..4000) 字段相比,最多可以占用两倍的物理磁盘空间+ — 即使 存储在 LOB 中。非 SCSU 的浪费取决于所代表的数据和语言。

                      Unicode Compression Implementation:

                      SQL Server 使用 Unicode 标准压缩方案 (SCSU) 算法的实现来压缩存储在行或页压缩对象中的 Unicode 值。对于这些压缩对象,Unicode 压缩对于 nchar(n) 和 nvarchar(n) 列是自动的 [并且从未与 nvarchar(max) 一起使用]。

                      另一方面,PAGE 压缩(自 2014 年以来)仍然适用于 NVARCHAR(MAX) 列如果它们被写为行内数据。所以缺少 SCSU 感觉就像“缺少优化” ”。与 SCSU 不同,页面压缩结果会因共享的前导前缀(即重复值)而有很大差异。

                      但是,由于避免了隐式转换,使用 NVARCHAR(MAX) 可能仍然“更快”,即使使用 OPENJSON 等函数的 IO 成本更高。这是隐式转换开销取决于使用的相对成本以及是否在过滤之前或之后触摸该字段。在 VARCHAR(MAX) 列中使用 2019 年的 UTF-8 排序规则时也存在同样的转换问题。

                      使用 NVARCHAR(1-4000) 还需要约 8000 字节行配额的 N*2 字节,而 NVARCHAR(MAX) 只需要 24 字节。整体设计和使用需要一起考虑,以考虑具体的实施细节。

                      +在我的数据库/数据/架构中,通过使用两列(读取时合并),可以将磁盘空间使用量减少约 40%,同时仍支持溢出的文本值。 SCSU 虽然有其缺陷,但却是一种非常聪明且未被充分利用的方法,可以更有效地存储 Unicode。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-02-04
                        • 1970-01-01
                        • 2010-09-27
                        • 2012-07-16
                        • 1970-01-01
                        • 2011-04-26
                        相关资源
                        最近更新 更多