我正在构建一个表来跟踪数据库中特定对象的历史记录。 目前我有以下专栏:
HistoryId int IDENTITY(1,1) NOT NULL
HistoryDate datetimeoffset(7) NOT NULL
HistoryTypeId int NOT NULL
HistoryDetails nvarchar(max) NULL
在大多数情况下,每个历史项目都将通过HistoryTypeId自我解释,因此HistoryDetails将为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
答案 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)并强制用户适应你的数据库设计,而不是相反。