在SQL Server 2005中,将所有字符字段设置为nvarchar(MAX)而不是显式指定长度(例如nvarchar(255))有什么缺点吗?(除了不能在数据库级别限制字段长度之外)


当前回答

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

ok, here's my feelings simply on the issue of business and data layer logic. It depends, if your DB is a shared resource between systems that share business logic then of course it seems a natural place to enforce such logic, but its not the BEST way to do it, the BEST way is to provide an API, this allows the interaction to be tested and keeps business logic where it belongs, it keeps systems decoupled, it keeps your tiers within a system decoupled. If however your database is supposed to be serving only one application, then lets get AGILE in thinking, what's true now? design for now. If and when such access is needed, provide an API to that data.

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

其他回答

有趣的链接:当你可以使用文本时,为什么要使用VARCHAR ?

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

我检查了一些文章,并从http://www.sqlservercentral.com/Forums/Topic1480639-1292-1.aspx找到了有用的测试脚本 然后将其更改为NVARCHAR(10) vs NVARCHAR(4000) vs 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或文本字段的原因是,你不能执行在线索引重建,即REBUILD WITH online = ON,即使与SQL Server企业版。

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

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

因此,即使没有存储在LOB中,具有相同文本内容的NVARCHAR(1..4000)字段所占用的物理磁盘空间也是NVARCHAR(1..4000)字段的两倍。非scsu浪费取决于所表示的数据和语言。

Unicode压缩实现:

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

另一方面,PAGE压缩(自2014年以来)仍然适用于NVARCHAR(MAX)列,如果它们被写入行内数据。所以缺乏SCSU感觉就像“缺少优化”。与SCSU不同,基于共享前导前缀(例如。重复的值)。

然而,使用NVARCHAR(MAX)可能仍然“更快”,即使使用OPENJSON这样的函数会有更高的IO成本,因为它避免了隐式转换。这是一种隐式转换开销,它取决于使用的相对成本,以及字段是在过滤之前还是过滤之后被处理的。在VARCHAR(MAX)列中使用2019年的UTF-8排序规则时也存在同样的转换问题。

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

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