web-dev-qa-db-fra.com

Y a-t-il des inconvénients à toujours utiliser nvarchar (MAX)?

Dans SQL Server 2005, la création de tous les champs de caractères nvarchar (MAX) présente-t-elle des inconvénients plutôt que de spécifier explicitement une longueur, par ex. nvarchar (255)? (En dehors de l'évident, vous ne pouvez pas limiter la longueur du champ au niveau de la base de données)

325
stucampbell

La même question a été posée sur les forums MSDN:

De la publication originale (beaucoup plus d'informations là-bas):

Lorsque vous stockez des données dans une colonne VARCHAR (N), les valeurs sont physiquement stockées de la même manière. Mais lorsque vous le stockez dans une colonne VARCHAR (MAX), derrière l'écran, les données sont traitées comme une valeur TEXT. Il faut donc un traitement supplémentaire pour traiter une valeur VARCHAR (MAX). (seulement si la taille dépasse 8000)

VARCHAR (MAX) ou NVARCHAR (MAX) est considéré comme un "type de grande valeur". Les types de grande valeur sont généralement stockés "hors ligne". Cela signifie que la ligne de données aura un pointeur sur un autre emplacement où la "grande valeur" est stockée ...

143
David Kreps

C'est une bonne question et il a énoncé en dehors de l'évidence…

Les inconvénients pourraient inclure:

Répercussions sur les performances L'optimiseur de requêtes utilise la taille du champ pour déterminer le plan d'exécution le plus efficace.

"1. L'espace disponible dans les extensions et les pages de la base de données est flexible. Ainsi, lors de l'ajout d'informations au champ à l'aide de update, votre base de données devrait créer un pointeur si les nouvelles données sont plus longues que les précédentes insérées. devenir fragmenté = performances inférieures dans presque tout, de l'index à la suppression, en passant par les insertions. " http://sqlblogcasts.com/blogs/simons/archive/2006/02/28/Why-use-anything-but -varchar_2800_max_2900_.aspx

Implications en matière d'intégration: il est difficile pour d'autres systèmes de savoir comment s'intégrer à votre base de données Croissance imprévisible des données Problèmes de sécurité éventuels, par exemple. vous pouvez planter un système en occupant tout l'espace disque

Il y a un bon article ici: http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1098157,00.html

47
alexmac

Parfois, vous souhaitez que le type de données donne un sens aux données qu'il contient.

Supposons, par exemple, que votre colonne ne devrait pas contenir plus de 20 caractères. Si vous définissez cette colonne en tant que VARCHAR (MAX), certaines applications malveillantes pourraient y insérer une longue chaîne et vous ne le saurez jamais ou ne pourrez en aucun cas l’empêcher.

La prochaine fois que votre application utilisera cette chaîne, en supposant que sa longueur soit modeste et raisonnable pour le domaine qu'elle représente, vous obtiendrez un résultat imprévisible et source de confusion.

28
Bill Karwin

D'après le lien fourni dans la réponse acceptée, il apparaît que:

  1. 100 caractères stockés dans un champ nvarchar(MAX) ne seront pas stockés différents de 100 caractères dans un champ nvarchar(100) - les données seront stockées en ligne et vous n'aurez pas le temps système nécessaire à la lecture et à l'écriture des données '. Donc pas de soucis là-bas.

  2. Si la taille est supérieure à 4 000, les données seraient automatiquement stockées "hors ligne", ce que vous souhaiteriez. Donc pas de soucis là non plus.

Pourtant...

  1. Vous ne pouvez pas créer d'index sur une colonne nvarchar(MAX). Vous pouvez utiliser l'indexation de texte intégral, mais vous ne pouvez pas créer d'index sur la colonne pour améliorer les performances de la requête. Pour moi, cela scelle l'accord ... c'est toujours un inconvénient de toujours utiliser nvarchar (MAX).

Conclusion:

Si vous voulez une sorte de "longueur de chaîne universelle" dans toute votre base de données, qui puisse être indexée et qui ne gaspille pas d'espace et de temps d'accès, vous pouvez utiliser nvarchar(4000).

25
Tim Abell

J'ai vérifié quelques articles et trouvé un script de test utile parmi ceux-ci: http://www.sqlservercentral.com/Forums/Topic1480639-1292-1.aspx Puis modifié pour comparer entre NVARCHAR (10) et NVARCHAR (4000) vs NVARCHAR (MAX) et je ne trouve pas la différence de vitesse lors de l’utilisation des nombres spécifiés, mais lors de l’utilisation de MAX. Vous pouvez tester par vous-même. J'espère que cette aide.

SET NOCOUNT ON;

--===== Test Variable Assignment 1,000,000 times using NVARCHAR(10)
DECLARE @SomeString NVARCHAR(10),
        @StartTime DATETIME;
--=====         
 SELECT @startTime = GETDATE();
 SELECT TOP 1000000
        @SomeString = 'ABC'
   FROM master.sys.all_columns ac1,
        master.sys.all_columns ac2;
 SELECT testTime='10', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(4000)
DECLARE @SomeString NVARCHAR(4000),
        @StartTime DATETIME;
 SELECT @startTime = GETDATE();
 SELECT TOP 1000000
        @SomeString = 'ABC'
   FROM master.sys.all_columns ac1,
        master.sys.all_columns ac2;
 SELECT testTime='4000', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(MAX)
DECLARE @SomeString NVARCHAR(MAX),
        @StartTime DATETIME;
 SELECT @startTime = GETDATE();
 SELECT TOP 1000000
        @SomeString = 'ABC'
   FROM master.sys.all_columns ac1,
        master.sys.all_columns ac2;
 SELECT testTime='MAX', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
19
QMaster

Voyez cela comme un autre niveau de sécurité. Vous pouvez concevoir votre table sans relation de clé étrangère - parfaitement valide - et garantir l'existence d'entités associées entièrement sur la couche de gestion. Cependant, les clés étrangères sont considérées comme de bonnes pratiques de conception car elles ajoutent un autre niveau de contrainte au cas où quelque chose gâcherait la couche de gestion. Il en va de même pour la limitation de la taille du champ et pour l’utilisation de varchar MAX.

13
Alex

Une raison de ne pas utiliser les champs max ou text est que vous ne pouvez pas exécuter reconstruction d'index en ligne i.e. RECONSTRUCTION AVEC ONLINE = ON même avec SQL Server Enterprise Edition.

8
Nick Kavadias

Le travail de la base de données consiste à stocker des données afin qu'elles puissent être utilisées par l'entreprise. Pour rendre ces données utiles, il est essentiel de veiller à ce qu’elles aient un sens. Le fait d'autoriser une personne à saisir un nombre illimité de caractères pour son prénom ne garantit pas des données significatives.

L'intégration de ces contraintes dans la couche de gestion est une bonne idée, mais cela ne garantit pas que la base de données restera intacte. Le seul moyen de garantir que les règles de données ne sont pas enfreintes consiste à les appliquer au niveau le plus bas possible dans la base de données.

4
Tom H

Mauvaise idée quand vous savez que le champ sera dans une plage définie, de 5 à 10 caractères par exemple. Je pense que je n’utiliserais max que si je n’étais pas sûr de la longueur. Par exemple, un numéro de téléphone ne devrait jamais dépasser un certain nombre de caractères.

Pouvez-vous honnêtement dire que vous n'êtes pas sûr de la longueur approximative requise pour chaque champ de votre table?

Je comprends ce que vous voulez dire - il y a des champs que je considérerais certainement utiliser varchar (max).

Fait intéressant, les documents MSDN résument bien la situation:

Utilisez varchar lorsque la taille des entrées de données de colonne varie considérablement. Utilisez varchar (max) lorsque la taille des entrées de données de colonne varie considérablement et peut dépasser 8 000 octets.

Il y a ne discussion intéressante sur la question ici .

4
RichardOD

Le seul problème que j'ai constaté est que nous développons nos applications sur SQL Server 2005 et que, dans un cas, nous devons prendre en charge SQL Server 2000. Je viens d'apprendre que façon simple que SQL Server 2000 ne fonctionne pas comme l'option MAX pour varchar ou nvarchar.

4
mattruma

Un problème est que si vous devez utiliser plusieurs versions de SQL Server, le MAX ne fonctionnera pas toujours. Donc, si vous travaillez avec des bases de données héritées ou dans toute autre situation impliquant plusieurs versions, vous feriez mieux de faire très attention.

3
TheTXI

Comme indiqué plus haut, il s’agit principalement d’un compromis entre stockage et performances. Au moins dans la plupart des cas.

Cependant, au moins un autre facteur doit être pris en compte lors du choix de n/varchar (Max) sur n/varchar (n). Les données vont-elles être indexées (par exemple, un nom de famille)? Puisque la définition de MAX est considérée comme un objet LOB, tout élément défini comme MAX n'est pas disponible pour l'indexation. et sans index, toute recherche impliquant les données en tant que prédicat dans une clause WHERE va être forcée dans une analyse de table complète, ce qui représente la pire performance que vous pouvez obtenir pour les recherches de données.

3
Harry Cooper

1) Le serveur SQL devra utiliser plus de ressources (mémoire allouée et temps CPU) pour traiter nvarchar (max) vs nvarchar (n) où n est un nombre spécifique au champ.

2) Qu'est-ce que cela signifie en termes de performance?

Sur SQL Server 2005, j'ai interrogé 13 000 lignes de données dans une table de 15 colonnes nvarchar (max). J'ai chronométré les requêtes à plusieurs reprises, puis modifié les colonnes en nvarchar (255) ou moins.

Les requêtes antérieures à l'optimisation étaient en moyenne de 2,0858 secondes. Les requêtes après la modification sont revenues en moyenne en 1,90 secondes. Cela représentait environ 184 millisecondes d'amélioration de la requête select * de base. C'est une amélioration de 8,8%.

3) Mes résultats sont en concurrence avec quelques autres articles indiquant une différence de performance. En fonction de votre base de données et de la requête, le pourcentage d'amélioration peut varier. Si vous n'avez pas beaucoup d'utilisateurs simultanés ou de très nombreux enregistrements, la différence de performances ne vous concernera pas. Cependant, la différence de performances augmentera avec l'augmentation du nombre d'enregistrements et du nombre d'utilisateurs simultanés.

2
WWC

Si toutes les données d'une ligne (pour toutes les colonnes) ne prendraient jamais raisonnablement 8 000 caractères ou moins, la conception au niveau de la couche de données devrait l'imposer.

Le moteur de base de données est beaucoup plus efficace tout en conservant tout le stockage d'objets blob. Plus vous pouvez limiter une ligne, mieux c'est. Plus il y a de rangées dans une page, mieux c'est. La base de données fonctionne simplement mieux quand elle doit accéder à moins de pages.

1
Matt Spradley

Lien intéressant: Pourquoi utiliser un VARCHAR quand vous pouvez utiliser TEXT?

Il s’agit de PostgreSQL et de MySQL. L’analyse des performances est donc différente, mais la logique du "caractère explicite" est toujours valable: pourquoi vous obliger à toujours vous préoccuper de quelque chose qui est pertinent un petit pourcentage du temps? Si vous avez enregistré une adresse électronique dans une variable, vous utiliseriez une "chaîne" et non une "chaîne limitée à 80 caractères".

1
orip

support du système hérité. Si vous avez un système qui utilise les données et que l'on s'attend à ce qu'il ait une certaine longueur, la base de données est un bon endroit pour appliquer la longueur. Ce n'est pas idéal, mais les systèmes existants ne sont parfois pas idéaux. = P

1
Tony

Mes tests ont montré qu'il existe des différences lors de la sélection.

CREATE TABLE t4000 (a NVARCHAR(4000) NULL);

CREATE TABLE tmax (a NVARCHAR(MAX) NULL);

DECLARE @abc4 NVARCHAR(4000) = N'ABC';

INSERT INTO t4000
SELECT TOP 1000000 @abc4
    FROM
    master.sys.all_columns ac1,
    master.sys.all_columns ac2;

DECLARE @abc NVARCHAR(MAX) = N'ABC';

INSERT INTO tmax
SELECT TOP 1000000 @abc
    FROM
    master.sys.all_columns ac1,
    master.sys.all_columns ac2;

SET STATISTICS TIME ON;
SET STATISTICS IO ON;

SELECT * FROM dbo.t4000;
SELECT * FROM dbo.tmax;
1
Kvasi

J'ai eu un fichier UDF qui a rempli les chaînes et mis la sortie à varchar (max). Si cela a été utilisé directement au lieu de revenir à la taille appropriée pour la colonne en cours de réglage, les performances étaient très médiocres. J'ai fini par donner une longueur arbitraire au format udf avec une grosse note au lieu de compter sur tous les appelants du format udf pour redéfinir la taille de la chaîne.

1
Cade Roux

Un inconvénient est que vous allez concevoir autour d'une variable imprévisible et que vous ignorerez probablement au lieu de tirer parti de la structure de données interne de SQL Server, composée progressivement de lignes, de pages et d'étendues.

Ce qui me fait penser à alignement de la structure de données en C, et qu'être conscient de l'alignement est généralement considéré comme une bonne chose (TM). Idée similaire, contexte différent.

Page MSDN pour pages et étendues

Page MSDN pour Row-Overflow Data

0
tsundoku

Le principal inconvénient que je peux voir est que, disons, vous avez ceci:

Lequel vous donne le plus d'informations sur les données nécessaires pour l'interface utilisateur?

Cette

            CREATE TABLE [dbo].[BusData](
                [ID] [int] IDENTITY(1,1) NOT NULL,
                [RecordId] [nvarchar](MAX) NULL,
                [CompanyName] [nvarchar](MAX) NOT NULL,
                [FirstName] [nvarchar](MAX) NOT NULL,
                [LastName] [nvarchar](MAX) NOT NULL,
                [ADDRESS] [nvarchar](MAX) NOT NULL,
                [CITY] [nvarchar](MAX) NOT NULL,
                [County] [nvarchar](MAX) NOT NULL,
                [STATE] [nvarchar](MAX) NOT NULL,
                [Zip] [nvarchar](MAX) NOT NULL,
                [PHONE] [nvarchar](MAX) NOT NULL,
                [COUNTRY] [nvarchar](MAX) NOT NULL,
                [NPA] [nvarchar](MAX) NULL,
                [NXX] [nvarchar](MAX) NULL,
                [XXXX] [nvarchar](MAX) NULL,
                [CurrentRecord] [nvarchar](MAX) NULL,
                [TotalCount] [nvarchar](MAX) NULL,
                [Status] [int] NOT NULL,
                [ChangeDate] [datetime] NOT NULL
            ) ON [PRIMARY]

Ou ca?

            CREATE TABLE [dbo].[BusData](
                [ID] [int] IDENTITY(1,1) NOT NULL,
                [RecordId] [nvarchar](50) NULL,
                [CompanyName] [nvarchar](50) NOT NULL,
                [FirstName] [nvarchar](50) NOT NULL,
                [LastName] [nvarchar](50) NOT NULL,
                [ADDRESS] [nvarchar](50) NOT NULL,
                [CITY] [nvarchar](50) NOT NULL,
                [County] [nvarchar](50) NOT NULL,
                [STATE] [nvarchar](2) NOT NULL,
                [Zip] [nvarchar](16) NOT NULL,
                [PHONE] [nvarchar](18) NOT NULL,
                [COUNTRY] [nvarchar](50) NOT NULL,
                [NPA] [nvarchar](3) NULL,
                [NXX] [nvarchar](3) NULL,
                [XXXX] [nvarchar](4) NULL,
                [CurrentRecord] [nvarchar](50) NULL,
                [TotalCount] [nvarchar](50) NULL,
                [Status] [int] NOT NULL,
                [ChangeDate] [datetime] NOT NULL
            ) ON [PRIMARY]
0
carlos martini