Utilisation de texte MAX ou d'un texte plus spécifique et plus petit

22

Quelqu'un passait en revue mon code DDL pour créer des tableaux et a suggéré, quand il a vu que j'ai vu utiliser des VARCHAR(256)champs pour du texte, je m'attends à être assez petit, comme un prénom ou autre, que je devrais toujours utiliser VARCHAR(MAX)et lié Pourquoi utiliser autre chose que varchar (max ) . Je l'ai lu mais il semblait daté, car il se concentrait sur 2005, et ne semblait pas offrir de véritable justification pour allouer potentiellement jusqu'à 2 Go par ligne sur tous les champs de texte.

Du point de vue des performances, du stockage, etc., comment décider de l'utilisation VARCHAR(MAX)ou d'un type plus petit et plus spécifique pour les versions modernes de SQL Server? (par exemple, 2008, 2012, 2014)

Phrancis
la source

Réponses:

31

Dois-je toujours utiliser (n)varchar(max)pour les colonnes de texte?

Non.

Pour SQL Server, les maxtypes de données ne doivent être spécifiés qu'en l'absence d'alternative. Il convient plutôt de choisir le type de base correct ( varcharou nvarchar) et de spécifier une longueur maximale explicite appropriée aux données à stocker.

Le stockage physique est identique, que la colonne soit tapée comme varchar(n)ou varchar(max), ce n'est donc pas le problème.

Les raisons de ne pas choisir (n)varchar(max)partout tournent autour des fonctionnalités, de la qualité du plan et des performances.

Une liste exhaustive n'est probablement pas pratique, mais entre autres, des maxcolonnes:

traits

  • Exiger une contrainte distincte pour appliquer une longueur maximale
  • Ne peut pas être une clé dans un index (donc pas de contraintes uniques non plus)
  • Peut empêcher DDL en ligne (y compris les reconstructions d'index et l'ajout d'une nouvelle colonne non nulle)
  • Ne sont généralement pas pris en charge pour les fonctionnalités «plus récentes», par exemple columnstore
  • Consultez la documentation du produit pour connaître les fonctionnalités et limitations plus spécifiques. Le schéma général est qu'il existe des limitations et des restrictions gênantes autour maxdes types de données. Toutes les limitations et effets secondaires ne sont pas documentés.

Performance

  • Exiger une manipulation spéciale dans le moteur d'exécution, pour tenir compte de la taille potentiellement très grande. En règle générale, cela implique d'utiliser un chemin de code moins efficace, avec une interface de streaming
  • Peut avoir des conséquences imprévues similaires pour le code externe (et d'autres composants SQL Server comme SSIS), qui doivent également être préparés pour gérer des données jusqu'à 2 Go
  • Sont supposés avoir une largeur de 4 000 octets dans les calculs d'allocation de mémoire. Cela risque d'entraîner une réservation de mémoire excessive, ce qui limite la simultanéité et pousse les pages d'index et de données précieuses hors de la mémoire cache
  • Désactivez plusieurs optimisations de performances importantes
  • Peut prolonger la durée du verrouillage
  • Peut empêcher l'optimiseur de choisir un plan de recherche (non dynamique)
  • Empêche les filtres d'être poussés dans les analyses et recherche comme résidu
  • Peut augmenter la pression et la contention de tempdb (selon la version), car les variables et les paramètres sont également susceptibles d'être tapés de manière maxà correspondre aux définitions de colonne

En résumé, il y a tellement d'effets secondaires subtils (et indésirables) à utiliser inutilement le maxspécificateur que cela n'a aucun sens de le faire. La «commodité» mineure de l'utilisation d'une seule déclaration n'est pas une sorte de compensation.

Évaluez chaque type dans son contexte, utilisez le type de base correct ( varcharou nvarchar) et une longueur explicite sensible.

Lectures complémentaires:

Paul White dit GoFundMonica
la source
8

Cela va se lire comme la réponse d'un paranoïaque, mais il n'y a pas que des considérations de stockage et de performances.

La base de données elle-même ne contrôle pas ses clients, et on ne peut pas supposer que les clients insèrent toujours en toute sécurité les entrées utilisateur - même si une base de données est conçue pour être utilisée uniquement avec une application .net qui utilise Entity Framework pour encapsuler les transactions et garantir les requêtes paramétrées sont systématiquement utilisés, vous ne pouvez pas savoir que ce sera toujours le cas.

Je ne saurais pas exactement comment faire cela, mais en faisant tous les champs de texte varchar(max), si un client a des problèmes avec Bobby Tables et / ou les paramètres de vos procédures stockées le sont également varchar(max), vous facilitez la tâche d'un attaquant une valeur de paramètre valide mais intelligemment mauvaise qui peut faire des choses que les clients ne sont pas censés faire - quoi que ce soit.

En limitant la longueur à ce que vous réellement besoin, vous n'êtes pas de protection vous de ces attaques intelligentes (je ne suis même pas sûr de ce qu'il est en fait appelé, je me souviens juste de lire à ce sujet un certain temps), mais vous ne dites pas " allez-y, essayez de me donner un script de 2 Go à exécuter "soit.

Mathieu Guindon
la source
Ce qu'elle appelle est probablement "injection" ("injection SQL", plus précisément).
Andriy M
@AndriyM ouais, pour une raison quelconque, je pensais aux attaques de troncature SQL (MS semble avoir supprimé le lien que j'avais mis en signet), mais c'est essentiellement l'exploitation des varchar(not-max)paramètres, donc j'ai un peu mis un pied dans la bouche ici. Mais oui, l'injection SQL serait applicable ici. Je devrais peut-être reformuler un peu cette réponse.
Mathieu Guindon