J'ai besoin de créer une large table dénormalisée avec beaucoup de colonnes décimales (26,8) (moins de 1024 colonnes, la plupart des colonnes seraient nulles ou nulles). Je connais environ 8060 octets par limite de ligne, j'ai donc essayé de créer un tableau avec une compression de page. Le code ci-dessous crée un tableau, insère une ligne et interroge la taille de la ligne. La taille des lignes est bien en dessous de la limite, mais si j'essaie d'ajouter une colonne décimale (26,8) de plus à la table, l'opération échoue avec l'erreur "La création ou la modification de la table 't1' a échoué car la taille de ligne minimale serait 8074, y compris 1256 octets de surcharge interne. ". Existe-t-il un moyen de créer une table unique avec autant de colonnes?
drop table t1
GO
create table t1(c1 decimal(26, 8) null)
with (data_compression = page)
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'alter table t1 add c' + convert(varchar, @i) + ' decimal(26, 8) null';
execute (@sql);
set @i += 1;
end;
GO
insert into t1(c1) select 0
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'update t1 set c' + convert(varchar, @i) + ' = 0';
execute (@sql);
set @i += 1;
end;
GO
select max_record_size_in_bytes from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
GO
DECIMAL(26, 8) NULL
champs dans une table, sans compression de page ou compression décimale. En activant la compression vardécimale mais pas la page, la surcharge passe à plus de 1 K. Il y a une chance extérieure que vous puissiez stocker plus de champs par page sans vardécimal, selon vos valeurs.Réponses:
La limite que vous rencontrez n'a rien à voir avec les données stockées sur la page. Le calcul est effectué en fonction des types de données des colonnes. C'est pourquoi vous rencontrez l'erreur sans aucune donnée dans le tableau. La compression aggrave cette limite. Vous pouvez lire les détails techniques derrière les frais généraux ici .
Vous pouvez contourner ce problème en utilisant des colonnes SPARSE . Cela signifie qu'il sera possible que les insertions échouent en fonction de ce que vous insérez, mais vous pouvez contourner la limite de 8060 octets. Le code suivant montre que vous pouvez très bien créer 1023 colonnes:
Cependant, toutes les restrictions qui l'entourent (lire l'article lié) peuvent le rendre inapproprié pour votre cas d'utilisation. Plus précisément, seules les
NULL
valeurs (non0
) sont optimisées pour occuper très peu d'espace. Si vous essayez d'insérer trop de0
s dans une seule ligne, vous obtiendrez une erreur. Voici ce que je vois lorsque j'essaie d'insérer des0
valeurs 1023 :Je suppose que si vous deveniez vraiment désespéré, vous pourriez créer les colonnes à la
VARCHAR(27)
place. Les colonnes de longueur variable peuvent être déplacées hors de la page afin que vous puissiez dépasser la limite de 8060 octets dans la définition de la table, mais l'insertion de certaines combinaisons de valeurs échouera. SQL Server vous en avertit lors de la création de la table:La compression de page ou de ligne peut être utile si vous optez pour l'
VARCHAR(27)
approche. Cela minimisera l'espace utilisé par les deux0
etNULL
. AvecVARCHAR(27)
je suis capable d'insérer très bien 10230
valeurs.la source
En dehors des aspects techniques et des solutions de rechange proposées (en utilisant des
VARCHAR(27)
colonnes) discutés dans la réponse de @ Joe , je remets en question la " nécessité de créer [un] tableau dénormalisé large" tel qu'exprimé par le PO Sauf s'il existe une exigence technique étrange que toutes ces colonnes doit être dans une seule table, je suggère / recommande de les répartir sur autant de tables "frères" que nécessaire. Les tables fratries étant des tables qui:IDENTITY
colonne (et pas de FK pour les autres)IDENTITY
Ici, vous divisez la ligne logique sur deux ou plusieurs tables physiques. Mais c'est essentiellement ce qu'est la normalisation de toute façon, et ce que les bases de données relationnelles sont conçues pour gérer.
Dans ce scénario, vous encourez un espace supplémentaire utilisé en dupliquant le PK, et une complexité de requête supplémentaire en raison de la nécessité soit
INNER JOIN
des tables ensemble (fréquemment mais pas toujours, sauf si toutes lesSELECT
requêtes utilisent toutes les colonnes, mais cela ne se produit généralement pas) ou créez une transaction explicite versINSERT
ouUPDATE
entre eux (DELETE
peut être gérée viaON DELETE CASCADE
set sur le FK).CEPENDANT, vous bénéficiez des avantages d'un modèle de données approprié avec des types de données natifs appropriés, et pas de supercherie qui pourrait avoir des conséquences imprévues plus tard. Même si l'utilisation
VARCHAR(27)
permet à cela de fonctionner au niveau technique, je ne pense pas que le stockage de décimales sous forme de chaînes soit dans votre / le meilleur intérêt du projet.Donc, si vous "n'avez besoin" que d'une seule table car vous ne réalisez pas qu'une seule entité logique n'a pas besoin d'être représentée physiquement dans un seul conteneur, n'essayez pas de forcer tout cela dans une seule table quand cela fonctionnera. gracieusement sur plusieurs tables.
L'exemple ci-dessous illustre le concept de base:
INSTALLER
TESTER
Retour:
la source