Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Contournement des colonnes maximales de SQL Server limitant la taille d'enregistrement de 1024 et 8 Ko

Ce n'est tout simplement pas possible. Voir Inside the Moteur de stockage :Anatomie d'un enregistrement

En supposant que votre table ressemble à ceci.

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

Puis même une ligne avec tous les NULL les valeurs utiliseront le stockage suivant.

  • Bits d'état A de 1 octet
  • Bits d'état B de 1 octet
  • Décalage du nombre de colonnes de 2 octets
  • 125 octets NULL_BITMAP (1 bit par colonne pour 1 000 colonnes)

Il s'agit donc de 129 octets garantis déjà utilisés (il en reste 7 931).

Si l'une des colonnes a une valeur qui n'est pas non plus NULL ou une chaîne vide, vous avez également besoin d'espace pour

  • Nombre de colonnes de longueur variable de 2 octets (il reste 7 929).
  • N'importe où entre 2 et 2 000 octets pour le tableau de décalage de colonne.
  • Les données elles-mêmes.

Le tableau de décalage de colonne consomme 2 octets par colonne de longueur variable sauf si cette colonne et toutes les colonnes ultérieures sont également de longueur nulle. Donc mise à jour col_1000 forcerait les 2000 octets entiers à être utilisés lors de la mise à jour de col_1 n'utiliserait que 2 octets.

Ainsi, vous pouvez remplir chaque colonne avec 5 octets de données et en tenant compte des 2 octets chacun dans le tableau de décalage de colonne, cela ajouterait jusqu'à 7 000 octets, ce qui est dans les 7 929 restants.

Cependant, les données que vous stockez sont de 102 octets (51 nvarchar caractères) afin que cela puisse être stocké hors ligne avec un pointeur de 24 octets vers les données réelles restant dans la ligne.

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

Donc, le meilleur des cas serait que vous puissiez stocker 304 colonnes de ces données de longueur et c'est si vous mettez à jour à partir de col_1 , col_2 , ... . Si col_1000 contient des données alors le calcul est

FLOOR(5929/24) = 247

Pour NTEXT le calcul est similaire sauf il peut utiliser un pointeur de 16 octets ce qui vous permettrait de comprimer les données dans quelques colonnes supplémentaires

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

La nécessité de suivre tous ces pointeurs hors ligne pour tout SELECT contre la table serait probablement très préjudiciable à la performance.

Script pour tester ceci

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)