在SQL Server 2005中,使所有字符字段都为nvarchar(MAX)而不是显式指定长度(例如nvarchar(255))是否有任何缺点?(除了显而易见的那一句,您无法在数据库级别限制字段长度)
在SQL Server 2005中,使所有字符字段都为nvarchar(MAX)而不是显式指定长度(例如nvarchar(255))是否有任何缺点?(除了显而易见的那一句,您无法在数据库级别限制字段长度)
Answers:
在MSDN论坛上提出了相同的问题:
从原始帖子(那里有更多信息):
当您将数据存储到VARCHAR(N)列时,这些值实际上以相同的方式存储。但是,当将其存储到VARCHAR(MAX)列时,在屏幕后面会将数据作为TEXT值处理。因此,在处理VARCHAR(MAX)值时,需要一些其他处理。(仅当大小超过8000时)
VARCHAR(MAX)或NVARCHAR(MAX)被视为“大值类型”。大值类型通常存储在“行外”。这意味着数据行将具有指向另一个存储“大值”的位置的指针。
N/VARCHAR(MAX)
” 没有缺点,因为“只有在大小超过8000的情况下”才会进行其他处理。因此,仅在必要时才产生成本,并且数据库的限制较少。我读错了吗?似乎您几乎总是想要N/VARCHAR(MAX)
而不是N/VARCHAR(1-8000)
……
sp_tableoptions
:msdn.microsoft.com/zh-cn/library/ms173530.aspx。VARCHAR(255)类型也可以从行中移出,提到的“开销”对于MAX和255可能是完全相同的。当MAX类型与TEXT类型变得不同时,它将MAX类型与TEXT类型进行比较(完全不同的API进行操作,不同的存储空间等)。它没有提到实际的差异:没有索引,没有对MAX类型的在线操作
这是一个公平的问题,除了明显的问题,他确实做了陈述。
缺点可能包括:
对性能的影响查询优化器使用字段大小来确定最有效的执行计划
“ 1.在扩展名和数据库页面中的空间分配是灵活的。因此,当使用更新向该字段添加信息时,如果新数据的长度大于先前插入的数据的长度,数据库将必须创建一个指针。数据库文件将变得零散=几乎所有性能(从索引到删除,更新和插入)的性能降低。“ 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
varchar(max)
。
根据接受的答案中提供的链接,看来:
一个nvarchar(MAX)
字段中存储的100个字符将与一个字段中的100个字符存储相同nvarchar(100)
-数据将以内联方式存储,并且您将没有“行外”读取和写入数据的开销。所以在那里没有后顾之忧。
如果大小大于4000,则数据将自动“按行存储”,这正是您想要的。因此,那里也不用担心。
然而...
nvarchar(MAX)
列上创建索引。您可以使用全文索引,但不能在列上创建索引以提高查询性能。对我来说,这很划算……始终使用nvarchar(MAX)是绝对不利的。结论:
如果您希望在整个数据库中使用一种“通用字符串长度”,可以对其进行索引并且不会浪费空间和访问时间,则可以使用nvarchar(4000)
。
nvarchar(max)
-就像string
在C#中一样?-但第3点)(索引问题)给出了答案。
nvarchar(4000)
有时您希望数据类型对其中的数据施加某种意义。
举例来说,您有一列的长度不应超过20个字符。如果您将该列定义为VARCHAR(MAX),则某些流氓应用程序可能会在其中插入一个长字符串,而您永远不会知道,或者有任何防止它的方法。
下次您的应用程序使用该字符串时,假设该字符串的长度对于它表示的域而言是适中且合理的,则您将遇到无法预料和令人困惑的结果。
我检查了一些文章,并从中找到了有用的测试脚本: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或text字段的原因是,即使使用SQL Server Enterprise Edition ,也无法执行联机索引重建,即REBUILD WITH ONLINE = ON。
当您知道该字段将在5到10个字符的设定范围内时,这是个坏主意。我想如果不确定长度是多少,只会使用max。例如,电话号码永远不会超过一定数量的字符。
可以诚实地说,您不确定表中每个字段的近似长度要求吗?
不过,我的意思是正确的-我肯定会考虑使用varchar(max)的某些字段。
有趣的是,MSDN文档对其进行了很好的总结:
当列数据条目的大小相差很大时,请使用varchar。当列数据条目的大小相差很大,并且大小可能超过8,000个字节时,请使用varchar(max)。
数据库的工作是存储数据,以便企业可以使用它。使数据有用的一部分是确保数据有意义。允许某人输入无限数量的姓氏并不能确保有意义的数据。
在业务层中建立这些约束是一个好主意,但这并不能确保数据库保持完整。保证不违反数据规则的唯一方法是在数据库中尽可能最低的级别实施它们。
一个问题是,如果您必须使用多个版本的SQL Server,则MAX不会始终有效。因此,如果您使用的是传统数据库或涉及多个版本的任何其他情况,则最好格外小心。
1)处理nvarchar(max)与nvarchar(n)时,SQL服务器将不得不利用更多的资源(分配的内存和cpu时间),其中n是特定于该字段的数字。
2)这对性能意味着什么?
在SQL Server 2005上,我从具有15个nvarchar(max)列的表中查询了13,000行数据。我对查询反复计时,然后将列更改为nvarchar(255)或更小。
优化之前的平均查询时间为2.0858秒。更改后的查询平均返回1.90秒。与基本的select *查询相比,这大约提高了184毫秒。那是8.8%的改善。
3)我的结果与其他几篇文章一致,这些文章表明两者之间存在性能差异。根据您的数据库和查询,改进百分比可能会有所不同。如果您没有很多并发用户或很多记录,那么性能差异对您来说就不是问题。但是,性能差异将随着更多记录和并发用户的增加而增加。
我有一个udf,它会填充字符串并将输出放入varchar(max)。如果直接使用此方法而不是将其转换为要调整的色谱柱的合适尺寸,则性能会很差。我最终将udf放到带有大音符的任意长度上,而不是依靠udf的所有调用方将字符串重新投射为较小的大小。
我的测试表明选择时存在差异。
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;
有趣的链接: 为什么可以在使用TEXT时使用VARCHAR?
它是关于PostgreSQL和MySQL的,所以性能分析是不同的,但是“显式性”的逻辑仍然成立:为什么要强迫自己始终担心与某事有关的事情呢?如果您将电子邮件地址保存到变量,则将使用“字符串”而不是“限于80个字符的字符串”。
我可以看到的主要缺点是,假设您有以下内容:
哪一项能为您提供有关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]
首先,我考虑了一下,然后又想了。这涉及性能,但是同样可以作为一种文档形式来了解字段的实际大小。当该数据库位于更大的生态系统中时,它确实会强制执行。我认为关键是要允许,但只能在合理范围内。
好的,这只是我对业务和数据层逻辑问题的感觉。这取决于,如果您的数据库是共享业务逻辑的系统之间的共享资源,那么执行该逻辑当然是很自然的地方,但这不是执行此逻辑的最佳方式,最佳方式是提供一个API,这允许进行测试的交互,并将业务逻辑保持在其所属位置,使系统保持解耦,使系统中的各个层保持解耦。但是,如果您的数据库仅应服务于一个应用程序,那么请让AGILE进行思考,现在情况如何?现在设计。如果以及何时需要这种访问,请提供该数据的API。
显然,这只是理想选择,如果您正在使用现有系统,则很有可能至少在短期内需要以不同的方式进行操作。