Detta är helt enkelt inte möjligt. Se Inuti Storage Engine:Anatomy of a record
Förutsatt att ditt bord är ungefär så här.
CREATE TABLE T1(
col_1 varchar(8000) NULL,
col_2 varchar(8000) NULL,
/*....*/
col_999 varchar(8000) NULL,
col_1000 varchar(8000) NULL
)
Sedan även en rad med alla NULL
värden kommer att använda följande lagring.
- 1 byte statusbitar A
- 1 byte statusbitar B
- 2 byte kolumnantal förskjutning
- 125 byte
NULL_BITMAP
(1bit
per kolumn för 1 000 kolumner)
Så det är garanterat 129 byte förbrukade redan (återstår 7 931).
Om någon av kolumnerna har ett värde som inte är NULL
eller en tom sträng då behöver du också plats för
- 2 byte kolumnantal med variabel längd (återstår 7 929).
- Var som helst mellan 2 - 2000 byte för kolumnoffsetmatrisen.
- Själva data.
Kolumnoffsetmatrisen förbrukar 2 byte per kolumn med variabel längd förutom om den kolumnen och alla senare kolumner också har noll längd. Så uppdaterar col_1000
skulle tvinga hela 2000 byte att användas medan uppdatering av col_1
skulle bara använda 2 byte.
Så du kan fylla varje kolumn med 5 byte data och när man tar hänsyn till de 2 byte vardera i kolumnoffset-matrisen skulle det lägga till upp till 7 000 byte, vilket är inom de 7 929 återstående.
Datan du lagrar är dock 102 byte (51 nvarchar
tecken) så att detta kan lagras utanför raden med en pekare på 24 byte till de faktiska data som finns kvar i raden.
FLOOR(7929/(24 + 2)) = 304
Så det bästa fallet skulle vara att du kan lagra 304 kolumner av denna längddata och det är om du uppdaterar från col_1
, col_2
, ...
. Om col_1000
innehåller data då är beräkningen
FLOOR(5929/24) = 247
För NTEXT
beräkningen är liknande förutom att den kan använda en 16 byte pekare
vilket skulle tillåta dig att klämma in data i några extra kolumner
FLOOR(7929/(16 + 2)) = 440
Behovet av att följa alla dessa off row-pekare för någon SELECT
mot bordet skulle sannolikt vara mycket skadligt för prestanda.
Skript för att testa detta
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)