Isso simplesmente não é possível. Veja Dentro do Mecanismo de armazenamento:anatomia de um registro
Supondo que sua tabela seja algo assim.
CREATE TABLE T1(
col_1 varchar(8000) NULL,
col_2 varchar(8000) NULL,
/*....*/
col_999 varchar(8000) NULL,
col_1000 varchar(8000) NULL
)
Em seguida, até mesmo uma linha com todos os
NULL
valores usarão o seguinte armazenamento. - bits de status de 1 byte A
- bits de status de 1 byte B
- Deslocamento da contagem de colunas de 2 bytes
- 125 bytes
NULL_BITMAP
(1bit
por coluna para 1.000 colunas)
Portanto, são 129 bytes garantidos já usados (deixando 7.931).
Se alguma das colunas tiver um valor que não seja
NULL
ou uma string vazia, então você também precisa de espaço para - Contagem de colunas de comprimento variável de 2 bytes (deixando 7.929).
- Qualquer lugar entre 2 e 2.000 bytes para a matriz de deslocamento da coluna.
- Os próprios dados.
A matriz de deslocamento de coluna consome 2 bytes por coluna de comprimento variável exceto se essa coluna e todas as colunas posteriores também tiverem comprimento zero. Atualizando
col_1000
forçaria que todos os 2.000 bytes fossem usados ao atualizar col_1
usaria apenas 2 bytes. Assim, você pode preencher cada coluna com 5 bytes de dados e, ao levar em consideração os 2 bytes de cada na matriz de deslocamento da coluna, isso somaria 7.000 bytes, o que está dentro dos 7.929 restantes.
No entanto, os dados que você está armazenando são 102 bytes (51
nvarchar
caracteres) para que isso possa ser armazenado fora da linha com um ponteiro de 24 bytes para os dados reais restantes na linha. FLOOR(7929/(24 + 2)) = 304
Portanto, o melhor caso seria armazenar 304 colunas com esses dados de comprimento e isso se você estiver atualizando de
col_1
, col_2
, ...
. Se col_1000
contém dados, então o cálculo é FLOOR(5929/24) = 247
Para
NTEXT
o cálculo é semelhante, exceto que pode usar um ponteiro de 16 bytes
o que permitiria que você comprimisse dados em algumas colunas extras FLOOR(7929/(16 + 2)) = 440
A necessidade de seguir todos esses ponteiros de linha para qualquer
SELECT
contra a mesa provavelmente seria altamente prejudicial ao desempenho. Script para testar isso
DROP TABLE T1
/* Create table with 1000 columns*/
DECLARE @CreateTableScript nvarchar(max) = 'CREATE TABLE T1('
SELECT @CreateTableScript += 'col_' + LTRIM(number) + ' VARCHAR(8000),'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 1000
ORDER BY number
SELECT @CreateTableScript += ')'
EXEC(@CreateTableScript)
/* Insert single row with all NULL*/
INSERT INTO T1 DEFAULT VALUES
/*Updating first 304 cols succeed. Change to 305 and it fails*/
DECLARE @UpdateTableScript nvarchar(max) = 'UPDATE T1 SET '
SELECT @UpdateTableScript += 'col_' + LTRIM(number) + ' = REPLICATE(1,1000),'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 304
ORDER BY number
SET @UpdateTableScript = LEFT(@UpdateTableScript,LEN(@UpdateTableScript)-1)
EXEC(@UpdateTableScript)