sql >> Databasteknik >  >> RDS >> Sqlserver

Arbeta runt SQL Server maximala kolumner begränsa 1024 och 8 kb poststorlek

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 (1 bit 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)


  1. Skapa en databas med MySQL Workbench från befintligt schema/modell

  2. Hur får man dummyvärde för XML-tom tag i tabell med Oracle?

  3. Returnera ISO-veckonummer från ett datum i SQL Server (T-SQL)

  4. SQL:Lägg till kolumn med inkrementellt id till SELECT