Ответ 1
Храните его в строгом соответствии. Покрытия SQL Server уже хранит столбцы MAX в отдельной "единице распределения" с SQL 2005. См. Таблица и организация индексов. Фактически это точно так же, как хранение столбца MAX в собственной таблице, но без какого-либо недостатка явно.
Наличие явной таблицы на самом деле будет медленнее (из-за ограничения внешнего ключа) и потребляет больше места (из-за дублирования DetaiID). Не говоря уже о том, что для этого требуется больше кода, а ошибки вводятся... написанием кода.
Обновление
Чтобы проверить фактическое местоположение данных, простой тест может показать это:
use tempdb;
go
create table a (
id int identity(1,1) not null primary key,
v_a varchar(8000),
nv_a nvarchar(4000),
m_a varchar(max),
nm_a nvarchar(max),
t text,
nt ntext);
go
insert into a (v_a, nv_a, m_a, nm_a, t, nt)
values ('v_a', N'nv_a', 'm_a', N'nm_a', 't', N'nt');
go
select %%physloc%%,* from a
go
Псевдо-столбец %%physloc%%
покажет фактическое физическое местоположение строки, в моем случае это была страница 200:
dbcc traceon(3604)
dbcc page(2,1, 200, 3)
Slot 0 Column 2 Offset 0x19 Length 3 Length (physical) 3
v_a = v_a
Slot 0 Column 3 Offset 0x1c Length 8 Length (physical) 8
nv_a = nv_a
m_a = [BLOB Inline Data] Slot 0 Column 4 Offset 0x24 Length 3 Length (physical) 3
m_a = 0x6d5f61
nm_a = [BLOB Inline Data] Slot 0 Column 5 Offset 0x27 Length 8 Length (physical) 8
nm_a = 0x6e006d005f006100
t = [Textpointer] Slot 0 Column 6 Offset 0x2f Length 16 Length (physical) 16
TextTimeStamp = 131137536 RowId = (1:182:0)
nt = [Textpointer] Slot 0 Column 7 Offset 0x3f Length 16 Length (physical) 16
TextTimeStamp = 131203072 RowId = (1:182:1)
Все значения столбцов, но TEXT и NTEXT, были сохранены в строке, включая типы MAX.
После изменения параметров таблицы и вставки новой строки (sp_tableoption не влияет на существующие строки), типы MAX были выселены в их собственное хранилище:
sp_tableoption 'a' , 'large value types out of row', '1';
insert into a (v_a, nv_a, m_a, nm_a, t, nt)
values ('2v_a', N'2nv_a', '2m_a', N'2nm_a', '2t', N'2nt');
dbcc page(2,1, 200, 3);
Обратите внимание, что столбцы m_a и nm_a теперь являются Textpointer в блоке выделения LOB:
Slot 1 Column 2 Offset 0x19 Length 4 Length (physical) 4
v_a = 2v_a
Slot 1 Column 3 Offset 0x1d Length 10 Length (physical) 10
nv_a = 2nv_a
m_a = [Textpointer] Slot 1 Column 4 Offset 0x27 Length 16 Length (physical) 16
TextTimeStamp = 131268608 RowId = (1:182:2)
nm_a = [Textpointer] Slot 1 Column 5 Offset 0x37 Length 16 Length (physical) 16
TextTimeStamp = 131334144 RowId = (1:182:3)
t = [Textpointer] Slot 1 Column 6 Offset 0x47 Length 16 Length (physical) 16
TextTimeStamp = 131399680 RowId = (1:182:4)
nt = [Textpointer] Slot 1 Column 7 Offset 0x57 Length 16 Length (physical) 16
TextTimeStamp = 131465216 RowId = (1:182:5)
Для незавершенности завершения мы также можем принудительно вывести одно из немакс-полей из строки:
update a set v_a = replicate('X', 8000);
dbcc page(2,1, 200, 3);
Обратите внимание, как столбец v_a хранится в хранилище Row-Overflow:
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
v_a = [BLOB Inline Root] Slot 0 Column 2 Offset 0x19 Length 24 Length (physical) 24
Level = 0 Unused = 99 UpdateSeq = 1
TimeStamp = 1098383360
Link 0
Size = 8000 RowId = (1:176:0)
Итак, как уже отмечали другие, типы MAX хранятся в строках по умолчанию, если они подходят. Для многих проектов DW это было бы неприемлемо, потому что типичные нагрузки DW должны сканировать или, по крайней мере, сканировать диапазон, поэтому следует использовать sp_tableoption ..., 'large value types out of row', '1'
. Обратите внимание, что это не влияет на существующие строки, в моем тесте даже не на перестройку индекса, поэтому опция должна быть включена раньше.
Для большинства загрузок типа OLTP, хотя факт, что типы MAX хранятся в строке, если это возможно, на самом деле является преимуществом, поскольку шаблон доступа OLTP предназначен для поиска, а ширина строки мало влияет на него.
Тем не менее, в отношении исходного вопроса: отдельная таблица не нужна. Включение опции large value types out of row
позволяет получить тот же результат при бесплатной стоимости разработки/теста.