sql >> Database teknologi >  >> RDS >> Sqlserver

Omgå SQL Server maksimale kolonner begrænser 1024 og 8 kb poststørrelse

Dette er simpelthen ikke muligt. Se Inde i Storage Engine:Anatomy of a record

Forudsat at dit bord er noget som dette.

CREATE TABLE T1(
    col_1 varchar(8000) NULL,
    col_2 varchar(8000) NULL,
    /*....*/
    col_999 varchar(8000) NULL,
    col_1000 varchar(8000) NULL
) 

Så endda en række med alle NULL værdier vil bruge følgende lager.

  • 1 byte statusbit A
  • 1 byte statusbit B
  • 2 bytes kolonneantal offset
  • 125 bytes NULL_BITMAP (1 bit pr. kolonne for 1.000 kolonner)

Så det er garanteret 129 bytes brugt allerede (efterlader 7.931).

Hvis nogen af ​​kolonnerne har en værdi, der hverken er NULL eller en tom streng så skal du også have plads til

  • 2 bytes variabel længde kolonneantal (efterlader 7.929).
  • Hvor som helst mellem 2 - 2000 bytes for kolonneoffset-arrayet.
  • Selve dataene.

Kolonneoffset-arrayet bruger 2 bytes pr. kolonne med variabel længde undtagen hvis den kolonne og alle senere kolonner også er nul længde. Så opdaterer col_1000 ville tvinge hele 2000 bytes til at blive brugt, mens opdatering af col_1 ville bare bruge 2 bytes.

Så du kan udfylde hver kolonne med 5 bytes data, og når du tager højde for de 2 bytes hver i kolonneoffset-arrayet, ville det tilføje op til 7.000 bytes, hvilket er inden for de resterende 7.929.

De data, du gemmer, er dog 102 bytes (51 nvarchar tegn), så dette kan gemmes uden for rækken med en 24 byte pointer til de faktiske data, der er tilbage i rækken.

FLOOR(7929/(24 + 2)) = 304

Så det bedste tilfælde ville være, at du kunne gemme 304 kolonner af disse længdedata, og det er, hvis du opdaterer fra col_1 , col_2 , ... . Hvis col_1000 indeholder data, så er beregningen

FLOOR(5929/24) = 247

For NTEXT beregningen ligner, bortset fra den kan bruge en 16 byte pointer som ville give dig mulighed for at presse data ind i et par ekstra kolonner

FLOOR(7929/(16 + 2)) = 440

Behovet for at følge alle disse off-row pointers for enhver SELECT mod bordet ville sandsynligvis være yderst skadelig for ydeevnen.

Script til at teste dette

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)


  1. Fix Msg 241 "Konvertering mislykkedes ved konvertering af dato og/eller tid fra tegnstreng" i SQL Server

  2. Datamigreringer

  3. MySQL-krypterede kolonner

  4. INSERT IGNORE øger den automatiske stigningstæller, selvom der ikke er tilføjet nogen post?