Jef*_*mer 4 sql t-sql sql-server database-design data-modeling
我正在构建一个表来跟踪数据库中特定对象的历史记录.目前我有以下列:
HistoryId int IDENTITY(1,1) NOT NULL
HistoryDate datetimeoffset(7) NOT NULL
HistoryTypeId int NOT NULL
HistoryDetails nvarchar(max) NULL
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,每个历史项目都将通过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
Run Code Online (Sandbox Code Playgroud)
您不能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'
Run Code Online (Sandbox Code Playgroud)
这将仅包括50
从您HistoryDetails
进入索引键的第一个字符(将在LIKE
条件中搜索),以及包含在列中的所有内容.
如果您完全确定永远不会搜索超过50
字符长度的字符串,则可以省略包含的列并使用此字符:
SELECT COUNT(*)
FROM History
WHERE HistoryTypeId = 123
AND HistoryDetailsIndex = 'string_prefix_up_to_50_characters'
Run Code Online (Sandbox Code Playgroud)
这将使索引更短.
但是,如果您提供的字符串长度超过50
字符数,则会失败,因此如果您绝对不会搜索长字符串,请使用它.