Necesito crear una amplia tabla desnormalizada con muchas columnas decimales (26,8) (menos del límite de 1024 columnas, la mayoría de las columnas serían nulas o cero). Sé acerca de la limitación de 8060 bytes por fila, así que intenté crear una tabla con compresión de página. El siguiente código crea una tabla, inserta una fila y consulta el tamaño de la fila. El tamaño de la fila está muy por debajo del límite, pero si intento agregar una columna decimal más (26,8) a la tabla, la operación falla con el error "Error al crear o modificar la tabla 't1' porque el tamaño mínimo de la fila sería 8074, incluyendo 1256 bytes de sobrecarga interna ". ¿Hay alguna forma de crear una sola tabla con tantas columnas?
drop table t1
GO
create table t1(c1 decimal(26, 8) null)
with (data_compression = page)
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'alter table t1 add c' + convert(varchar, @i) + ' decimal(26, 8) null';
execute (@sql);
set @i += 1;
end;
GO
insert into t1(c1) select 0
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'update t1 set c' + convert(varchar, @i) + ' = 0';
execute (@sql);
set @i += 1;
end;
GO
select max_record_size_in_bytes from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
GO
DECIMAL(26, 8) NULL
campos en una tabla, sin compresión de página o compresión decimal. Al habilitar la compresión vardecimal pero no la página, la sobrecarga salta a más de 1 K. Existe la posibilidad externa de que pueda almacenar más campos por página sin vardecimal, dependiendo de sus valores.Respuestas:
El límite con el que se encuentra no tiene nada que ver con los datos almacenados en la página. El cálculo se realiza en función de los tipos de datos de las columnas. Es por eso que te encuentras con el error sin ningún dato en la tabla. La compresión empeora este límite. Puede leer sobre los detalles técnicos detrás de los gastos generales aquí .
Puede solucionar este problema utilizando columnas SPARSE . Eso significa que será posible que las inserciones fallen, dependiendo de lo que inserte, pero puede omitir el límite de 8060 bytes. El siguiente código muestra que puede crear 1023 columnas muy bien:
Sin embargo, todas las restricciones que lo rodean (lea el artículo vinculado) pueden hacer que esto no sea adecuado para su caso de uso. Específicamente, solo los
NULL
valores (no0
) están optimizados para ocupar muy poco espacio. Si intenta insertar demasiados correos0
electrónicos en una sola fila, obtendrá un error. Esto es lo que veo cuando intento insertar0
valores 1023 :Supongo que si realmente te desesperas podrías crear las columnas como en su
VARCHAR(27)
lugar. Las columnas de longitud variable se pueden mover fuera de la página para que pueda exceder el límite de 8060 bytes en la definición de la tabla, pero la inserción de ciertas combinaciones de valores fallará. SQL Server le advierte sobre esto al crear la tabla:La compresión de páginas o filas puede ser útil si sigue el
VARCHAR(27)
enfoque. Eso minimizará el espacio utilizado por ambos0
yNULL
. ConVARCHAR(27)
soy capaz de insertar 10230
valores muy bien.fuente
Fuera de los aspectos técnicos y la solución propuesta (usando
VARCHAR(27)
columnas) discutidas en la respuesta de @ Joe , cuestiono la " necesidad de crear [una] tabla desnormalizada amplia" como lo expresa el OP A menos que haya algún requisito técnico extraño de que todas estas columnas debe estar en una sola tabla, sugeriría / recomendaría distribuirlas en tantas tablas de "hermanos" como sea necesario. Las tablas hermanas son tablas que:IDENTITY
columna (y no FK para los demás)IDENTITY
Aquí está dividiendo la fila lógica en dos o más tablas físicas. Pero eso es esencialmente lo que es la normalización de todos modos, y qué bases de datos relacionales están diseñadas para manejar.
En este escenario, se incurre en algo de espacio adicional utilizado al duplicar la PK, y en una complejidad de consulta adicional debido a la necesidad de
INNER JOIN
unir las tablas (con frecuencia pero no siempre, a menos que todas lasSELECT
consultas usen todas las columnas, pero eso generalmente no sucede) o cree una Transacción explícita a ellosINSERT
oUPDATE
juntos (DELETE
puede manejarse a través delON DELETE CASCADE
conjunto en el FK).SIN EMBARGO, obtienes los beneficios de tener un modelo de datos adecuado con tipos de datos nativos y adecuados, y ningún truco que podría tener consecuencias imprevistas más adelante. Incluso si el uso
VARCHAR(27)
permite que esto funcione a nivel técnico, pragmáticamente no creo que almacenar decimales como cadenas sea lo mejor para su / el proyecto.Entonces, si solo está "necesitando" una sola tabla debido a que no se da cuenta de que una sola entidad lógica no necesita ser representada físicamente en un solo contenedor, entonces no intente forzar todo esto en una sola tabla cuando funcione con gracia en varias mesas.
El siguiente ejemplo ilustra el concepto básico:
PREPARAR
PRUEBA
Devoluciones:
fuente