Должен ли я использовать nvarchar (max) вместо столбца nvarchar (64) или как дополнительный столбец? - PullRequest
4 голосов
/ 14 сентября 2009

Я создаю таблицу для отслеживания истории конкретных объектов в моей базе данных. В настоящее время у меня есть следующие столбцы:

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

По большей части каждый элемент истории будет понятен через HistoryTypeId, поэтому HistoryDetails будет либо нулевым, либо очень маленьким. Но для пары типов истории данные будут большими. Можно ли использовать 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 ]

5 голосов
/ 14 сентября 2009

Нельзя сделать 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) и все в включенном столбце.

Если вы абсолютно уверены, что никогда не будете искать строку длиной более 50 символов, вы можете опустить включенный столбец и просто использовать это:

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

Это сделает индекс короче.

Однако это не удастся, если вы предоставите строку длиной более 50 символов, поэтому используйте ее, если вы абсолютно уверены, что никогда не будете искать длинные строки.

0 голосов
/ 14 сентября 2009

Сначала имейте в виду, что varchar (MAX) может хранить до 2 ГБ пространства, за кулисами он фактически использует значение TEXT, и впоследствии он использует больше обработки, чем varchar (8000) или меньше.

Если вы храните много меньших данных в varchar (max), они будут обрабатываться как обычный столбец varchar, если вы не превысите 8000, после чего они будут обрабатываться как varchar (max). *

Индексируется ли столбец или вы хотите его проиндексировать? Если это так, держитесь подальше от varchar (макс.).

Я бы просто выбрал более высокое значение, скажем, varchar (255), и заставил бы пользователей приспосабливаться к дизайну вашей базы данных, а не наоборот.

0 голосов
/ 14 сентября 2009

Поскольку вы используете nvarchar, вы уже платите накладные расходы записи переменной длины более чем вероятно, если только SQLServer не переопределит переменную длину для небольших случаев. Однако место на диске не должно меняться для коротких записей между nvarchar (64) и nvarchar (max). Они должны занимать столько места, сколько необходимо для размещения их данных. Обычно это число используется только для ограничения данных. Если вы не хотите ограничивать это, вы не должны платить штраф за использование тех двух, которые вы еще не платите.

...