sql >> Base de Datos >  >> RDS >> Sqlserver

¿Debo usar una columna varchar (max) en línea o almacenarla en una tabla separada?

Manténgalo en línea. Debajo de las cubiertas, SQL Server ya almacena las columnas MAX en una 'unidad de asignación' separada desde SQL 2005. Consulte Organización de tablas e índices. En efecto, esto 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 más lento (debido a la restricción de clave externa) y consumir más espacio (debido a la duplicación de DetaiID). Sin mencionar que requiere más código, y los errores se introducen al... escribir código.

texto alternativo http://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(en-us,SQL.100).gif

Actualizar

Para verificar la ubicación real de los datos, una simple prueba puede mostrarla:

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

El %%physloc%% la pseudocolumna mostrará la ubicación física real de la fila, en mi caso fue 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 columna excepto 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 las filas existentes), los tipos MAX se expulsaron a 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);

Observe cómo las columnas m_a y nm_a ahora son un Textpointer en la 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 completar bien, también podemos forzar uno de los campos no máximos fuera de la fila:

update a set v_a = replicate('X', 8000);
dbcc page(2,1, 200, 3);

Observe cómo se almacena la columna v_a en el almacenamiento de desbordamiento de filas:

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) 

Entonces, como ya han comentado otros, los tipos MAX se almacenan en línea de forma predeterminada, si encajan. Para muchos proyectos DW, esto sería inaceptable porque las cargas DW típicas deben escanear o al menos escanear rangos, por lo que sp_tableoption ..., 'large value types out of row', '1' debería ser usado. Tenga en cuenta que esto no afecta las filas existentes, en mi prueba ni siquiera en la reconstrucción del índice , por lo que la opción debe activarse antes.

Sin embargo, para la mayoría de las cargas de tipo OLTP, el hecho de que los tipos MAX se almacenen en línea si es posible es en realidad una ventaja, ya que el patrón de acceso OLTP es para buscar y el ancho de la fila tiene poco impacto en él.

Sin embargo, con respecto a la pregunta original:no es necesaria una mesa separada. Activar los large value types out of row La opción logra el mismo resultado a un costo gratuito para desarrollo/prueba.