Quand utiliser TINYINT sur INT?

91

En général, j'utilise toujours Ints. Je sais que , en théorie , ce n'est pas la meilleure pratique, cependant, puisque vous devez utiliser le plus petit type de données qui sera garanti pour stocker les données.

Par exemple, il est préférable de l'utiliser tinyintlorsque vous savez que les seules données que vous allez stocker sont 1, 0 ou nulles (avec une très faible chance de les étendre ultérieurement à 2 ou 3).

Cependant, la seule raison que je connaisse pour cela est pour des raisons de stockage - en utilisant 1 octet sur une ligne au lieu de 4 octets.

Quel est l’impact de l’utilisation tinyint(ou smallintmême bigint) sur la seule utilisation int, autre que l’économie d’espace sur votre disque dur?

Richard
la source
2
C'est une très belle quesiton (+1). MySQL a SELECT ... PROCEDURE ANALYZE () qui recommande en fait les plus petits types de données que la table devrait avoir pour un SELECT donné. C'était en partie l'inspiration derrière ma réponse.
RolandoMySQLDBA
3
Belle question, mais pour préciser la gamme tinyint est 0-255. Le champ de bits est 0 ou 1 (ou NULL). Le coût de stockage pour un tinyint est de 1 octet. Chaque champ de 8 bits dans une table coûtera 1 octet de stockage. msdn.microsoft.com/en-us/library/ms187745.aspx et msdn.microsoft.com/en-us/library/ms177603.aspx
billinkc
@ Billinkc Droite. C'est pourquoi j'ai mentionné la possibilité d'élargir la colonne pour inclure les valeurs 2 ou 3. Si vous incluez 2 ou 3, vous devez utiliser tinyint (à la plus petite échelle).
Richard
1
"Par exemple, il vaut mieux utiliser tinyint quand vous savez que les seules données que vous allez stocker sont 1, 0 ou nulles (avec une très petite chance de les agrandir à 2 ou 3 plus tard)." J'utiliserais un ENUM pour une telle chose. Celles-ci sont stockées sous forme de champs de bits et, comme beaucoup d'autres l'ont déjà souligné, de petites économies par enregistrement s'ajoutent aux économies importantes générées sur l'ensemble de la base de données, même davantage si la colonne est indexée.
2
@ user6665 I'd use an ENUM for such a thing.Pas dans SQL Server, vous ne le feriez pas, car il ne comporte aucune énumération.
underscore_d

Réponses:

92

L'espace disque est bon marché ... ce n'est pas la question!

Arrêtez de penser en termes d'espace de stockage, pensez plutôt au pool de tampons et à la bande passante de stockage . À l'extrême, cache du CPU et bande passante du bus mémoire . L'article lié fait partie de la série mettant en exergue les problèmes liés à une sélection de clé en cluster médiocre (INT, GUID ou GUID séquentiel), mais souligne la différence que les octets peuvent faire.

Le message primordial est la conception. La différence n'apparaîtra pas dans une base de données individuelle sur un serveur spécifié de manière appropriée jusqu'à ce que vous atteigniez le territoire VLDB, mais si vous pouvez enregistrer quelques octets, pourquoi ne pas le faire.

Je me souviens de l'environnement décrit dans une question précédente . Plus de 400 bases de données, d'une taille allant de 50 Mo à 50 Go, par instance SQL. Nettoyer quelques octets par enregistrement, par table et par base de données dans cet environnement peut faire toute la différence.

Mark Storey-Smith
la source
29

En plus des autres réponses ...

Les lignes et les entrées d'index sont stockées dans des pages de 8 000 pages. Ainsi, un million de lignes à 3 octets par ligne ne représente pas 3 Mo sur le disque: cela affecte le nombre de lignes par page ("densité de page").

La même chose s'applique à nvarchar to varchar, smalldatetime à datetime, int à tinyint, etc.

Edit, juin 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

Cet article dit

Les critères importants sont la cardinalité et le rapport de page à ligne.

Donc, le choix du type de données est important

gbn
la source
5
Bon point. Le pire exemple absolu est une ligne de 4028 octets constituée de colonnes de longueur entièrement fixe auxquelles vous souhaitez ajouter une colonne. Ajouter un smallint vous porterait à 4030 (2 lignes par page) mais un int vous poussera au-dessus de la limite (1 ligne par page, 4028 octets perdus par page).
Mark Storey-Smith
J'ai déjà fait un test de performance sur int vs bigint. Sauvegardez 1 million d’enregistrements, comparez temps et stockage, et récupérez-les un par un, en mesurant à nouveau les performances. Je n'ai pas vu de différences majeures. Je vais faire le même test de performance pour int vs tinyint. Je pense vraiment que cela peut être négligé pour 80% des applications, ce qui entraîne des types de données plus cohérents et des coûts de maintenance moindres.
Saeed Neamati
1
@SaeedNeamati Vous pouvez relire l'article de la réponse de Mark ( « Avez - vous déjà entendu ... Finissons - ce fait - nous inquiétons des performances plus tard ... Je l' entends tout le temps ... ») et GBN est ici . Je pense que la conclusion à la maison est que tout choix inefficace va montrer ses rayures à la bonne échelle, et l'intestin de OP ne se trompe pas.
Ruffin
14

Ce n'est pas seulement le stockage sur table qui compte. Si vous utilisez des index dans lesquels la colonne int fait partie d'une clé composée, vous voudrez naturellement que les pages d'index soient aussi complètes que possible, ce qui résulte en des entrées d'index aussi petites que possible.

Je m'attendrais certainement à constater que l'examen des entrées d'index dans les pages BTREE serait un peu plus rapide avec des types de données plus petits. Cependant, toute VARCHAR impliquée dans les entrées d'index compenserait (annulait) les gains de performances résultant de l'utilisation de TINYINT sur INT.

Néanmoins, si les entrées d'index ont des entrées composées et que toutes sont des entiers, plus les entiers sont petits, plus le nombre est élevé, mieux c'est et plus vite.

RolandoMySQLDBA
la source
13

Toutes les choses deviennent de plus en plus complexes lorsque les bases de données s'agrandissent:

  • les fenêtres de maintenance doivent être agrandies ou reprogrammées
  • sauvegardes (la sauvegarde complète de fin de journée devient un mangeur de temps absurde, vous avez donc besoin d'une sauvegarde différentielle ou même d'une journalisation et effectuez la sauvegarde complète une fois par semaine, voire une fois par mois)
  • performances maintanances devient un mangeur de temps (la création d'un index sur une table de plusieurs millions de lignes ne prend pas beaucoup de temps à exécuter) et doit être replanifiée et s'aggrave si la table est large ...
  • Et transmettre cette sauvegarde de 100 Go sur le réseau n’est pas ce que j’appelle du gâteau - en particulier si le réseau (pour une raison inconnue) est obstiné à laisser tomber la connexion sur la marque des 75 Go ... (s’est passé avec une installation sur laquelle je travaillais sauvegarde sur un lecteur mappé sur le réseau - réseau) ...

Et quels types de données ont à voir avec cela? TOUT. Utiliser des tailles de ligne plus grandes que nécessaire amène les pages de la base de données à se remplir plus tôt que nécessaire, voire à gaspiller de l'espace si la taille de la ligne est telle que plus d'un enregistrement ne peut être enregistré sur la page. Le résultat est qu'il faut plus de pages pour écrire et lire, plus de mémoire RAM est utilisée pour mettre en cache cette mémoire (les gros disques ont besoin de plus de mémoire). Et puisque vos types de données sont spécifiés plus volumineux que nécessaire sur le disque, vos index subiront le même problème - en particulier si vous mettez en cluster cette clé primaire composée de 2 colonnes BIGINT composites, car tout autre index créé copiera cette clé primaire implicitement dans leur définition.

Si vous savez que certaines colonnes d'une table auront des millions de lignes ou même une petite table qui passera de FK à plusieurs millions de lignes et ne nécessitera pas un entier de 4 octets pour stocker leurs données, mais un octet de 2 suffire - utilisez SMALLINT . Si des valeurs comprises entre 0 et 255 sont suffisantes, TINYINT . Un drapeau Oui / Non? Il y a BIT .

Fabricio Araujo
la source
9

Bien que pour tinyintvs, intil existe des différences claires telles que l’espace disque, les divisions de page et le temps de maintenance, il n’y en a pas varchar.

Alors, pourquoi ne pas déclarer tous les champs de texte comme étant varchar(4000)donné qu’ils ne vont utiliser que l’espace nécessaire? De plus, vous aurez la garantie que vos données ne seront jamais tronquées.

La réponse est bien sûr:

  1. Clarification de vos intentions (personne ne comprendra pourquoi un champ de nom doit comporter 4 000 caractères)
  2. Validation car vous voulez vous assurer que personne n'entre une biographie complète comme nom.

Ces mêmes raisons s’appliquent tinyintégalement.

yoel halb
la source
3
C'est un fil plus ancien, mais la clarification et la validation ne sont pas la seule raison. Si vous avez VARCHAR (4000) pour quelque chose qui devrait être VARCHAR (20), le plan de requête pensera que vos besoins en mémoire et en CPU correspondent à de multiples multiples de ce qu'ils devraient être pour cette colonne. Je n'ai pas pris le temps de le faire, mais je suppose que vous pouvez probablement le voir en consultant un plan de requête pour VARCHAR (20), puis en passant à VARCHAR (4000) et en vérifiant les coûts estimés.
3
@GeorgeShouse Démonstration de cela ici
Martin Smith