Manténgalo en línea. Bajo las cubiertas SQL Server ya almacena las columnas MAX en una 'unidad de asignación' separada desde SQL 2005. Ver Table and Index Organization. Esto en efecto es exactamente lo mismo que mantener la columna MAX en su propia tabla, pero sin ninguna desventaja de hacerlo explícitamente.
Tener una tabla explícita en realidad sería tanto más lenta (debido a la restricción de clave externa) y consumen más espacio (debido a la duplicación DetaiID). Sin mencionar que requiere más código, y los errores se introducen al ... escribir código.
alt text http://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(en-us,SQL.100).gif
actualización
Para comprobar la ubicación real de los datos, una prueba simple puede mostrar que:
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
La columna %%physloc%%
seudo mostrará la ubicación física real de la fila, en mi caso era la página 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)
Todos los valores de columnas, pero TEXT y NTEXT se almacenaron en línea, incluidos los tipos MAX.
Después de cambiar las opciones de la tabla e insertar una nueva fila (sp_tableoption no afecta a las filas existentes), los tipos MAX fueron desalojados en su propio almacenamiento:
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);
Nota cómo m_A y columnas nm_a son ahora una Textpointer en el unidad de asignación de 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)
Para sakeness terminación también puede forzar el uno de los campos no máximo fuera de la fila:
update a set v_a = replicate('X', 8000);
dbcc page(2,1, 200, 3);
Nota cómo la columna de la V_A se almacena en el almacenamiento de desbordamiento de fila:
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)
Así que, como otros ya han comentado, los tipos MAX se almacenan en línea por defecto, si se ajustan. Para muchos proyectos de DW, esto sería inaceptable porque las cargas típicas de DW deben escanear o, al menos, escanear el rango, por lo que se debe usar sp_tableoption ..., 'large value types out of row', '1'
. Tenga en cuenta que esto no afecta a las filas existentes, en mi prueba ni siquiera en la reconstrucción del índice, por lo que la opción debe activarse antes.
Para la mayoría de las cargas de tipo OLTP, aunque el hecho de que los tipos MAX se almacenen en línea si es posible es una ventaja, ya que el patrón de acceso OLTP es buscar y el ancho de fila tiene poco impacto en él.
Sin embargo, con respecto a la pregunta original: no es necesaria una tabla por separado. Al activar la opción large value types out of row
se obtiene el mismo resultado a un costo gratuito para desarrollo/prueba.
+! ¿Sería SQL Server almacenar un varchar (max) con 17 caracteres en una unidad de asignación separada? – Andomar
El comportamiento predeterminado es que no almacenará varchar (max) en el almacenamiento de LoB/asignaciones a menos que exceda la asignación, Cade Roux publicó un enlace a la configuración para alterar esto. – Andrew
Muy detallado - Gracias por su completitud Remus –