在SQL Server 2005中,将所有字符字段设置为nvarchar(MAX)而不是显式指定长度(例如nvarchar(255))有什么缺点吗?(除了不能在数据库级别限制字段长度之外)
当前回答
如果一行中的所有数据(对于所有列)不会合理地占用8000或更少的字符,那么数据层的设计应该强制执行这一点。
数据库引擎可以更有效地将所有内容排除在blob存储之外。限制行越小越好。一页中可以塞进的行越多越好。当数据库必须访问更少的页面时,它的性能会更好。
其他回答
一个缺点是,您将围绕一个不可预知的变量进行设计,您可能会忽略而不是利用内部SQL Server数据结构,逐步由Row(s)、Page(s)和Extent(s)组成。
这让我想到了C中的数据结构对齐,并且通常认为知道对齐是一件好事(TM)。相似的想法,不同的背景。
页面和区段的MSDN页面
行溢出数据的MSDN页面
我能看到的主要缺点是,假设你有这样的情况:
哪一个提供了关于UI所需数据的最多信息?
This
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]
我的测试表明,在选择时存在差异。
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;
我检查了一些文章,并从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
根据已接受的答案中提供的链接,似乎是:
存储在nvarchar(MAX)字段中的100个字符将与存储在nvarchar(100)字段中的100个字符没有区别-数据将内联存储,并且您不会有“行外”读取和写入数据的开销。所以不用担心。 如果大小大于4000,数据将自动“行外”存储,这是你想要的。所以也不用担心。
然而……
不能在nvarchar(MAX)列上创建索引。可以使用全文索引,但不能在列上创建索引以提高查询性能。对我来说,这就决定了……总是使用nvarchar(MAX)是一个明显的缺点。
结论:
如果你想要一种贯穿整个数据库的“通用字符串长度”,它可以被索引,并且不会浪费空间和访问时间,那么你可以使用nvarchar(4000)。
推荐文章
- 为什么历史上人们使用255而不是256作为数据库字段大小?
- 如何选择记录从过去24小时使用SQL?
- 如何为查询返回的每一行执行存储过程一次?
- 按IN值列表排序
- 如何使用SQL Server 2008做多个CASE WHEN条件?
- 计数在VARCHAR字段中字符串的出现次数?
- 如何选择多行填充常量?
- 修改一个MySQL列为AUTO_INCREMENT
- 如果没有使用EXISTS引入子查询,则只能在选择列表中指定一个表达式
- SQL Server -事务回滚错误?
- 如何在SQL中有效地计数列值的发生?
- 查询以列出数据库中每个表中的记录数量
- PostgreSQL列名区分大小写吗?
- 在WHERE子句中引用列别名
- 存储图像在SQL Server?