我应该使用nvarchar(max)代替nvarchar(64)列还是作为附加列?

时间:2009-09-14 15:22:19

标签: sql sql-server tsql database-design data-modeling

我正在构建一个表来跟踪数据库中特定对象的历史记录。 目前我有以下专栏:

HistoryId int IDENTITY(1,1) NOT NULL
HistoryDate datetimeoffset(7) NOT NULL 
HistoryTypeId int NOT NULL
HistoryDetails nvarchar(max) NULL

在大多数情况下,每个历史项目都将通过HistoryTypeId自我解释,因此HistoryDe​​tails将为Null或非常小。但是对于几种历史类型,细节数据会很大。是否可以使用nvarchar(max)表示所有记录,或者我应该将它拆开并为历史类型添加额外的列,这些列需要超过64个字符(见下文)?粗略估计,80%-90%的记录不需要超过64个字符的详细信息,表中将有数百万条记录。

HistoryId int IDENTITY(1,1) NOT NULL
HistoryDate datetimeoffset(7) NOT NULL 
HistoryTypeId int NOT NULL
HistoryDetails nvarchar(64) NULL
HistoryDetailsMore nvarchar(max) NULL

3 个答案:

答案 0 :(得分:5)

您不能将NVARCHAR(MAX)作为普通B-Tree索引中某个键的一部分(您仍然可以将其用作索引中的包含列)。

否则,只要列中的数据不超过行大小阈值,存储就会一样。

由于您可能无论如何都不会将此字段编入索引,因此最好将其创建为NVARCHAR(MAX)

即使您仍想索引它(例如,使用LIKE进行前缀搜索),您可以创建计算NVARCHAR(450)列,在该列上创建索引,并将其添加到您的列中查询粗略过滤。

有关详细信息,请参阅我的博客中的此条目:

如果您要仅对小列进行精确搜索,请创建一个计算列,将其编入索引并进行如下查询:

ALTER TABLE History ADD HistoryDetailsIndex AS SUBSTRING(HistoryDetails, 1, 50)

CREATE INDEX ix_mytable_typeid_details ON History (HistoryTypeId, HistoryDetailsIndex) INCLUDE (HistoryDetails)

SELECT  COUNT(*)
FROM    History
WHERE   HistoryTypeId = 123
        AND HistoryDetailsIndex LIKE 'string_prefix_up_to_50_characters%'
        AND HistoryDetails = 'string_prefix_up_to_50_characters_plus_everything_after_it'

这将仅包含50中的HistoryDetails个字符到索引键中(将在LIKE条件下搜索),以及所有内容都包含在列中。< / p>

如果您绝对不会搜索长度超过50个字符的字符串,则可以省略包含的列并使用它:

SELECT  COUNT(*)
FROM    History
WHERE   HistoryTypeId = 123
        AND HistoryDetailsIndex = 'string_prefix_up_to_50_characters'

这会缩短索引。

但是,如果您提供长度超过50个字符的字符串,则会失败,因此如果您绝对不会搜索长字符串,请使用它。

答案 1 :(得分:0)

由于您使用的是nvarchar,因此除非SQLServer覆盖小案例的变量长度,否则您已经支付了可变长度记录开销的可能性。但是,对于nvarchar(64)和nvarchar(max)之间的短记录,磁盘上的空间不应更改。它们应该只占用适合其数据所需的空间。通常,该数字仅用于约束数据。如果您不想限制它,那么您在使用那些尚未支付的费用之间不应该支付罚金。

答案 2 :(得分:0)

首先请注意,varchar(MAX)可以存储高达2gb的空间,在幕后实际使用TEXT值,然后使用比varchar(8000)更少的处理。

如果你在varchar(max)中存储了很多较小的数据,它将被视为普通的varchar列,除非你超过8000,之后它将被视为varchar(max)。

列是否已编入索引,或者您要将其编入索引?如果没有varchar(max)。

我会选择一个更高的值,比如说varchar(255)并强制用户适应你的数据库设计,而不是相反。