Dit kan gewoon niet. Zie Inside the Storage Engine:anatomie van een record
Ervan uitgaande dat uw tafel ongeveer zo is.
CREATE TABLE T1(
col_1 varchar(8000) NULL,
col_2 varchar(8000) NULL,
/*....*/
col_999 varchar(8000) NULL,
col_1000 varchar(8000) NULL
)
Dan zelfs een rij met allemaal NULL
waarden gebruiken de volgende opslag.
- 1 byte statusbits A
- 1 byte statusbits B
- Verschuiving kolomtelling van 2 bytes
- 125 bytes
NULL_BITMAP
(1bit
per kolom voor 1.000 kolommen)
Dus dat is een gegarandeerde 129 bytes die al opgebruikt zijn (waardoor er 7.931 overblijft).
Als een van de kolommen een waarde heeft die niet NULL
. is of een lege string dan heb je ook ruimte nodig voor
- 2 bytes variabele lengte kolomtelling (waardoor er 7.929 overblijven).
- Ergens tussen 2 - 2000 bytes voor de kolom-offset-array.
- De gegevens zelf.
De kolom-offset-array verbruikt 2 bytes per kolom met variabele lengte behalve als die kolom en alle latere kolommen ook een lengte van nul hebben. Dus update col_1000
zou dwingen om de volledige 2000 bytes te gebruiken tijdens het bijwerken van col_1
zou gewoon 2 bytes gebruiken.
Dus je zou elke kolom kunnen vullen met 5 bytes aan gegevens en als je rekening houdt met de 2 bytes elk in de kolom-offset-array, zou dat optellen tot 7.000 bytes, wat binnen de resterende 7.929 ligt.
De gegevens die u opslaat zijn echter 102 bytes (51 nvarchar
tekens) zodat dit buiten de rij kan worden opgeslagen met een 24-byte-aanwijzer naar de feitelijke gegevens die nog in de rij staan.
FLOOR(7929/(24 + 2)) = 304
Dus het beste geval zou zijn dat u 304 kolommen van deze lengtegegevens zou kunnen opslaan en dat is als u bijwerkt vanaf col_1
, col_2
, ...
. Als col_1000
gegevens bevat, dan is de berekening
FLOOR(5929/24) = 247
Voor NTEXT
de berekening is vergelijkbaar, behalve het kan een 16 byte pointer gebruiken
waarmee u gegevens in een paar extra kolommen kunt persen
FLOOR(7929/(16 + 2)) = 440
De noodzaak om al deze off-row-aanwijzingen te volgen voor elke SELECT
tegen de tafel zou waarschijnlijk zeer nadelig zijn voor de prestaties.
Script om dit te testen
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)