Quand vous concevez une table de base de données, comment choisissez-vous le type numérique de chaque colonne ?
« Mets INT pour les entiers. » « Prends BIGINT, on ne sait jamais. » « Il y a des décimales, donc FLOAT. » Si ces phrases vous sont familières, vous n’êtes pas seul. Mais ce type de réflexe peut engendrer des problèmes de performance, du gaspillage de stockage, et même des bugs critiques dans les calculs financiers à terme.
Exemple concret : remplacer INT par BIGINT sur une seule colonne d’une table de 100 millions de lignes ajoute environ 400 Mo de stockage. Ajoutez deux index, et l’écart dépasse 1 Go. À l’autre extrême, choisir INT pour une table de logs à forte volumétrie qui grandit de plusieurs millions de lignes par jour peut provoquer un crash par dépassement quelques années plus tard, paralysant toute votre application.
Et puis il y a FLOAT. La plupart des développeurs savent que 0.1 + 0.2 donne 0.30000000000000004 au lieu de 0.3. Pourtant, des colonnes FLOAT se retrouvent encore dans des tables de paiement en production, accumulant silencieusement des erreurs d’arrondi jusqu’à ce que les rapports mensuels de chiffre d’affaires ne correspondent plus.
Cet article est un guide complet des quatre types numériques SQL les plus importants — INT, BIGINT, DECIMAL et FLOAT — couvrant leurs différences, leurs compromis, et des règles de décision pratiques que vous pouvez appliquer immédiatement.
La conception de base de données est le socle de tout système logiciel. Pour les fondamentaux de la conception orientée objet, consultez le guide des principes SOLID. Pour choisir un langage de programmation, consultez le guide de comparaison des langages.
Aperçu des types numériques SQL
Commençons par la vue d’ensemble. Le tableau ci-dessous résume les principaux types numériques. Chaque section suivante approfondit le sujet.
| Type | Taille | Plage (approx.) | Précision | Usage typique |
|---|---|---|---|---|
| TINYINT | 1 octet | 0 – 255 / -128 – 127 | Exacte | Drapeaux, codes statut |
| SMALLINT | 2 octets | 0 – 65 535 | Exacte | Petits compteurs |
| INT | 4 octets | ~2,1 milliards / ~4,2 milliards | Exacte | IDs, quantités, comptages |
| BIGINT | 8 octets | ~9,2 × 10¹⁸ | Exacte | IDs de logs, clés primaires volumineuses |
| DECIMAL(M,D) | Variable | M chiffres (D décimales) | Exacte | Argent, taux de TVA, ratios |
| FLOAT | 4 octets | ±3,4 × 10³⁸ | Approximative | Température, données capteurs |
| DOUBLE | 8 octets | ±1,7 × 10³⁰⁸ | Approximative | Coordonnées GPS, statistiques |
Les quatre types qui comptent le plus au quotidien sont INT, BIGINT, DECIMAL et FLOAT. Maîtrisez ces quatre-là et vous gérerez la grande majorité des conceptions de bases de données sans problème.
Les types entiers (famille INT) — Le point de départ par défaut
Les entiers sont le type numérique le plus rapide, le plus économe en stockage et le plus fiable en SQL. Ils surpassent les autres en vitesse de calcul, efficacité des index et empreinte disque. Si une colonne n’a pas besoin de décimales, un type entier est toujours le bon choix.
MySQL propose cinq tailles d’entiers :
| Type | Taille | Plage SIGNED | Plage UNSIGNED |
|---|---|---|---|
| TINYINT | 1 octet | -128 à 127 | 0 à 255 |
| SMALLINT | 2 octets | -32 768 à 32 767 | 0 à 65 535 |
| MEDIUMINT | 3 octets | -8 388 608 à 8 388 607 | 0 à 16 777 215 |
| INT | 4 octets | -2 147 483 648 à 2 147 483 647 | 0 à 4 294 967 295 |
| BIGINT | 8 octets | -9,2 × 10¹⁸ à 9,2 × 10¹⁸ | 0 à ~1,84 × 10¹⁹ |
La règle d’or : si la valeur peut être représentée comme un entier, utilisez un type entier. Par exemple, si votre système gère les prix en centimes d’euros, price_cents INT fonctionne parfaitement. INT plafonne à environ 2,1 milliards, ce qui permet de gérer des montants jusqu’à 21 millions d’euros en centimes — largement suffisant pour la plupart des produits e-commerce.
Cas d’usage courants des entiers :
- IDs (clés primaires) : user_id, product_id, order_id
- Quantités : stock_quantity, cart_count
- Compteurs : login_count, view_count, retry_count
- Codes statut : order_status (0 = en attente, 1 = payé, 2 = expédié…)
- Drapeaux booléens : is_active, is_deleted (TINYINT avec 0/1)
Il n’y a aucune raison d’utiliser DECIMAL ou FLOAT pour l’un de ces cas. Les entiers sont le choix le plus rapide et le plus sûr.
INT vs. BIGINT — « Mieux vaut prévenir que guérir » est-il vraiment prudent ?
Le dilemme le plus courant dans le choix du type entier est INT contre BIGINT. La réponse courte : INT suffit dans la grande majorité des cas. La réponse longue montre pourquoi tout passer en BIGINT à l’aveugle est un anti-pattern coûteux.
Prenons d’abord conscience de l’échelle. INT UNSIGNED plafonne à environ 4,2 milliards. La France compte environ 68 millions d’habitants — à peine 1,6 % de la capacité d’un INT. Un service web avec 1 million d’utilisateurs pourrait stocker 4 000 entrées de logs par utilisateur et rester dans la plage d’un INT. Pour les IDs utilisateurs, produits et commandes, INT est presque toujours largement suffisant.
Alors quand BIGINT devient-il nécessaire ?
- Logs d’accès : Un site gérant 100 millions de pages vues par mois accumule 1,2 milliard de lignes par an. En 3–4 ans, le plafond d’INT est en vue
- Données IoT : 10 000 capteurs envoyant des données chaque seconde génèrent environ 315 milliards de lignes par an — bien au-delà de la capacité d’INT
- IDs distribués (Snowflake, etc.) : Ils encodent un horodatage, un ID de worker et un numéro de séquence en une seule valeur potentiellement très grande
- IDs de transactions : Un système de paiement traitant 1 million de transactions par jour atteint 3,65 milliards en 10 ans — dangereusement proche de la limite d’INT
Quantifions maintenant le coût de « mettre BIGINT partout » :
| Scénario | INT (4 octets) | BIGINT (8 octets) | Différence |
|---|---|---|---|
| 100M lignes × 1 colonne | 381 Mo | 762 Mo | +381 Mo |
| 100M lignes × 1 col + 2 index | 1,14 Go | 2,29 Go | +1,14 Go |
| Mémoire JOIN (estimation) | Référence | ~1,5–2× | Efficacité cache réduite |
Sur une table de 100 millions de lignes, passer une seule colonne plus deux index d’INT à BIGINT gaspille plus de 1,1 Go. Multipliez cela sur plusieurs colonnes et tables, et le total peut atteindre des dizaines de gigaoctets — augmentant les I/O disque, réduisant l’efficacité du buffer pool et ralentissant les requêtes.
Un guide de décision pratique :
| Rôle de la colonne | Type recommandé | Justification |
|---|---|---|
| ID utilisateur | INT UNSIGNED | Très peu de services dépassent 4,2 milliards d’utilisateurs |
| ID produit | INT UNSIGNED | Même raisonnement |
| ID commande | INT UNSIGNED ou BIGINT | Dépend du volume et de la durée de vie |
| ID log d’accès | BIGINT | Des milliards de lignes attendues par an |
| Snowflake / UUID numérique | BIGINT | Valeurs intrinsèquement grandes |
Ne fondez pas votre choix uniquement sur le nombre actuel de lignes. Ce qui compte, c’est le taux de croissance sur toute la durée de vie opérationnelle. Estimez les insertions annuelles, projetez sur 10 ans, et vérifiez si INT UNSIGNED (4,2 milliards) tiendra. Si ce n’est pas le cas, partez directement sur BIGINT.
UNSIGNED — Doubler la plage gratuitement
Dans MySQL et MariaDB, ajouter UNSIGNED à une colonne entière supprime la plage négative et double la plage positive sans coût de stockage supplémentaire. Un INT classique va d’environ -2,1 milliards à +2,1 milliards ; INT UNSIGNED va de 0 à 4,2 milliards — toujours 4 octets.
Les colonnes comme les IDs, quantités et compteurs ne sont jamais négatives. Il n’y a aucune raison de ne pas utiliser UNSIGNED pour elles.
CREATE TABLE users (n id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n age TINYINT UNSIGNED, u002du002d 0 u00e0 255, cu0027est largement suffisantn login_count INT UNSIGNED DEFAULT 0,n point INT UNSIGNED DEFAULT 0n);
La soustraction entre deux colonnes UNSIGNED peut provoquer un dépassement par le bas (underflow). Dans MySQL, SELECT a - b où a < b produit une valeur énorme (ou une erreur) car le résultat fait un « wrap around ». Si la soustraction est possible, utilisez CAST(a AS SIGNED) - CAST(b AS SIGNED) ou envisagez de garder la colonne en SIGNED.
Note : PostgreSQL ne supporte pas UNSIGNED. L’alternative classique est une contrainte CHECK (CHECK (id >= 0)) pour garantir des valeurs non négatives au niveau applicatif.
DECIMAL (NUMERIC) — Le seul choix correct pour l’argent
DECIMAL stocke les nombres comme des valeurs exactes en base 10. Contrairement à FLOAT, il ne convertit pas en binaire en interne : 0,1 est stocké exactement comme 0,1. Pour toute colonne où même une fraction de centime compte — prix, factures, TVA, soldes de comptes — DECIMAL est le seul type acceptable.
Pourquoi pas FLOAT ? Voyons le problème en action :
u002du002d Ce qui se passe avec FLOATnSELECT CAST(0.1 AS FLOAT) + CAST(0.2 AS FLOAT);nu002du002d Ru00e9sultat : 0.30000001192092896 (pas 0.3)nnu002du002d DECIMAL donne le ru00e9sultat justenSELECT CAST(0.1 AS DECIMAL(10,2)) + CAST(0.2 AS DECIMAL(10,2));nu002du002d Ru00e9sultat : 0.30 (exactement 0.30)
En quoi cette infime erreur est-elle importante en pratique ? Imaginez une boutique en ligne vendant un article à 11,99 €, traitant 50 000 commandes par mois :
- Avec FLOAT : Chaque ligne peut porter une erreur aussi minime que +0,000001, mais sur 50 000 lignes et de multiples calculs de TVA, les écarts d’arrondi s’accumulent. Multipliez par des centaines de références sur un an, et le grand livre dérive de plusieurs euros — suffisamment pour déclencher un contrôle fiscal
- Avec DECIMAL : Zéro dérive. Chaque agrégation est juste au centime près, à chaque fois
« Ce n’est qu’un millionième d’euro. » C’est vrai — mais en comptabilité, si les comptes ne tombent pas juste au centime, quelqu’un doit expliquer pourquoi. « On a utilisé le mauvais type de colonne » n’est pas une réponse qu’un commissaire aux comptes acceptera.
DECIMAL se déclare DECIMAL(M, D) où M est le nombre total de chiffres et D le nombre de décimales :
u002du002d DECIMAL(10,2) : 10 chiffres au total, 2 du00e9cimalesnu002du002d Valeur max : 99 999 999,99nnCREATE TABLE orders (n id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n subtotal DECIMAL(10,2) NOT NULL, u002du002d Montant HTn tax_rate DECIMAL(5,4) NOT NULL, u002du002d ex. 0.2000 (20 % TVA)n tax_amount DECIMAL(10,2) NOT NULL, u002du002d Montant TVAn total DECIMAL(10,2) NOT NULL u002du002d Total TTCn);
DECIMAL et NUMERIC sont synonymes dans le standard SQL. MySQL, PostgreSQL et SQL Server les traitent de manière identique. Choisissez-en un et restez cohérent dans tout votre code.
Dimensionner DECIMAL — Pourquoi DECIMAL(18,10) est presque toujours surdimensionné
Une autre erreur courante consiste à spécifier une précision excessive : DECIMAL(18,10) voire DECIMAL(30,15) « au cas où ». Cela gaspille du stockage et ralentit les agrégations.
La taille de stockage de DECIMAL est proportionnelle au nombre de chiffres. Dans MySQL, chaque groupe de 9 chiffres consomme 4 octets, avec des octets supplémentaires pour les restes :
| Type | Stockage (MySQL) | Exemple d’usage |
|---|---|---|
| DECIMAL(5,2) | 3 octets | Pourcentages (jusqu’à 99,99 %) |
| DECIMAL(10,2) | 5 octets | Prix (jusqu’à 99 999 999,99 €) |
| DECIMAL(12,4) | 6 octets | Taux de change (ex. 1,3456) |
| DECIMAL(18,10) | 9 octets | Surdimensionné pour la plupart des applications |
La bonne approche consiste à partir de la valeur maximale :
- Prix e-commerce : Si le prix le plus élevé est de quelques millions d’euros, DECIMAL(10,2) couvre jusqu’à 99 999 999,99 €
- Taux de TVA : En France, le taux normal est de 20 %, le taux réduit de 5,5 %. DECIMAL(5,4) couvre jusqu’à 99,9999 %
- Pourcentages de remise : 0–100 % tient dans DECIMAL(5,2)
- Taux de change : EUR/USD à 1,0845 — DECIMAL(12,4) offre une marge confortable
- Cryptomonnaies : La plus petite unité d’Ethereum (wei = 10⁻¹⁸ ETH) nécessite réellement DECIMAL(36,18) — un cas rare où une précision extrême est justifiée
Utiliser DECIMAL(18,10) pour une colonne de prix, c’est comme imprimer une note personnelle sur du papier A0. Dimensionnez la précision correctement, et vous économiserez du stockage et accélérerez vos requêtes.
FLOAT / DOUBLE — La vitesse au prix de l’exactitude
FLOAT et DOUBLE sont des types à virgule flottante qui représentent les nombres décimaux au format binaire IEEE 754. Cela leur confère un avantage majeur et une limitation intrinsèque.
L’avantage est clair : 4 octets fixes (FLOAT) ou 8 octets (DOUBLE) peuvent représenter une plage de valeurs énorme. FLOAT seul couvre ±3,4 × 10³⁸, et le matériel de calcul flottant du CPU rend l’arithmétique extrêmement rapide.
La limitation est qu’ils stockent des approximations, pas des valeurs exactes. Le décimal 0,1 devient le binaire périodique infini 0,000110011001100… qui doit être arrondi pour tenir dans un nombre fini de bits. C’est la cause fondamentale du fameux problème « 0,1 + 0,2 ≠ 0,3 ».
FLOAT est le bon choix quand de petites erreurs d’arrondi n’affectent pas le résultat :
- Relevés de température : Un capteur industriel indique 23,45 °C avec une précision intrinsèque de ±0,1 °C. Une erreur de stockage de ±0,0001 °C n’a aucune signification
- Coordonnées GPS : Six décimales en latitude/longitude correspondent à ~11 cm de précision. DOUBLE préserve jusqu’à 15 chiffres significatifs — une précision sub-millimétrique qui dépasse largement tout besoin réel
- Features de machine learning : Les modèles ML ont des millions voire des milliards de paramètres ; un micro-arrondi sur un poids individuel a un impact négligeable sur la précision globale
- Simulations physiques : La dynamique des fluides et l’analyse structurelle tirent parti de la vitesse de FLOAT, avec un contrôle de l’erreur au niveau algorithmique
- Agrégats statistiques : Moyennes, écarts-types et corrélations sont calculés à partir de données qui contiennent déjà du bruit statistique
Le choix entre FLOAT et DOUBLE se résume à la précision et au stockage :
| Type | Taille | Chiffres significatifs | Quand le choisir |
|---|---|---|---|
| FLOAT | 4 octets | ~7 | Données capteurs, stockage optimisé |
| DOUBLE | 8 octets | ~15 | Haute précision requise : GPS, calcul scientifique |
Stocker des coordonnées GPS en FLOAT ne donne que ~7 chiffres significatifs — environ 11 m de précision. Pour une application de cartographie, DOUBLE (~15 chiffres, sub-millimétrique) est le choix évident. Inversement, stocker des relevés de capteurs de température en DOUBLE est inutile quand le capteur lui-même n’est précis qu’à ±0,5 °C — FLOAT est amplement suffisant.
FLOAT vs. DECIMAL — Guide de décision rapide
En pratique, vous devez faire ce choix rapidement et avec assurance. Voici un tableau de référence :
| Cas d’usage | DECIMAL | FLOAT / DOUBLE |
|---|---|---|
| Prix, factures, facturation | ✓ | ✗ (jamais) |
| Taux de TVA, remises | ✓ | ✗ |
| Points fidélité / miles | ✓ (si fractionnaire) | ✗ |
| Poids d’inventaire (kg) | ✓ | △ |
| Température / humidité | △ | ✓ |
| Coordonnées GPS | △ | ✓ (DOUBLE) |
| Données capteurs | △ | ✓ |
| Features ML / scores | ✗ | ✓ |
| Valeurs statistiques (moyenne, etc.) | △ | ✓ |
La règle de base tient en trois lignes :
- De l’argent est en jeu → DECIMAL
- Mesure ou science → FLOAT / DOUBLE
- Pas sûr → DECIMAL (par précaution)
Retenez ces trois règles et vous vous tromperez rarement.
Cinq erreurs de conception courantes
Les erreurs de types numériques ont tendance à être invisibles en développement et ne se révèlent qu’en production. Voici les cinq plus fréquentes.
Erreur n°1 : Mettre BIGINT partout
L’esprit « plus gros, plus sûr » pousse les équipes à mettre BIGINT sur toutes les colonnes entières par défaut. Comme montré plus haut, cela peut gaspiller plus de 1 Go pour 100 millions de lignes sur une seule colonne plus ses index. Sur 10 tables avec 3 colonnes BIGINT chacune, cela représente environ 12 Go de stockage gaspillé — impactant directement les coûts d’hébergement cloud et l’efficacité du buffer pool.
Erreur n°2 : Utiliser FLOAT pour l’argent
C’est l’erreur la plus dangereuse de cette liste. Elle passe souvent tous les tests unitaires car les erreurs d’arrondi sont invisibles à petite échelle. Le problème émerge en production quand le volume de transactions augmente : « Le chiffre d’affaires mensuel ne correspond pas aux dépôts bancaires réels. » L’analyse de la cause racine prend des jours, et corriger rétroactivement des données financières stockées en FLOAT est extrêmement difficile.
Erreur n°3 : Surdimensionner la précision DECIMAL
Définir DECIMAL(30,15) « au cas où » gaspille du stockage et ralentit les requêtes d’agrégation. En dehors des cryptomonnaies (où 18 décimales sont réellement nécessaires), très peu de domaines métier nécessitent plus de 4 décimales.
Erreur n°4 : Ne pas anticiper le dépassement INT
Une table peut commencer avec quelques centaines d’insertions par jour, mais la croissance peut être exponentielle. INT SIGNED plafonne à ~2,1 milliards. Avec un AUTO_INCREMENT à 50 000 insertions/jour, cela laisse 117 ans de marge — mais les dumps de données de test, les trous d’ID et la croissance inattendue peuvent consommer cette marge plus vite que prévu. Surveillez régulièrement vos « high-water marks » d’AUTO_INCREMENT.
Erreur n°5 : Types incompatibles dans les JOINs
Si orders.user_id est INT mais users.id est BIGINT, chaque JOIN déclenche une conversion de type implicite. Dans MySQL, cela peut empêcher l’optimiseur d’utiliser les index, transformant une requête d’une milliseconde en un scan complet de table de plusieurs secondes. Assurez-vous toujours que les colonnes utilisées dans les JOINs partagent exactement le même type.
Types recommandés par cas d’usage
Utilisez ce tableau de référence rapide lors de la conception de nouvelles tables :
| Rôle de la colonne | Type recommandé | Notes |
|---|---|---|
| ID utilisateur | INT UNSIGNED | 4,2 milliards, c’est largement suffisant |
| ID produit | INT UNSIGNED | Même raisonnement |
| ID log / événement | BIGINT UNSIGNED | Des milliards de lignes par an |
| ID Snowflake | BIGINT | Valeurs intrinsèquement grandes |
| Prix produit | DECIMAL(10,2) | Max 99 999 999,99 € |
| Taux de TVA | DECIMAL(5,4) | ex. 0.2000 (20 %) |
| Taux de remise | DECIMAL(5,2) | ex. 15,50 % |
| Taux de change | DECIMAL(12,4) | ex. 1,0845 |
| Quantité en stock (entier) | INT UNSIGNED | Pas de décimales nécessaires |
| Poids (kg) | DECIMAL(8,3) | ex. 12345,678 |
| Température | FLOAT | La précision du capteur suffit |
| Latitude / Longitude GPS | DOUBLE | Haute précision requise |
| Feature ML | FLOAT | Vitesse plutôt que précision |
| Points (entier) | INT UNSIGNED | Pas de fractions |
| Points (fractionnaire) | DECIMAL(10,2) | Miles aériens, etc. |
| Position au classement | INT UNSIGNED | Les classements ne sont jamais négatifs |
| Drapeau booléen (0/1) | TINYINT UNSIGNED | Le BOOLEAN de MySQL en interne |
| Code statut | TINYINT ou SMALLINT | Dimensionner selon la plage de valeurs |
Partager un tel tableau au sein de votre équipe élimine la plupart des débats de choix de types lors des revues de code.
CREATE TABLE — Exemples concrets
Pour finir, voici trois définitions de tables prêtes pour la production. Remarquez comment chaque colonne utilise le type le plus petit adapté.
Exemple 1 : Produits e-commerce
CREATE TABLE products (n id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n name VARCHAR(255) NOT NULL,n price DECIMAL(10,2) NOT NULL DEFAULT 0.00, u002du002d Argent = DECIMALn tax_rate DECIMAL(5,4) NOT NULL DEFAULT 0.2000, u002du002d 20 % TVA = 0.2000n stock INT UNSIGNED NOT NULL DEFAULT 0, u002du002d Quantitu00e9 entiu00e8ren weight_kg DECIMAL(8,3), u002du002d Poids du0027expu00e9ditionn rating FLOAT, u002du002d Note moyenne utilisateurn is_active TINYINT UNSIGNED NOT NULL DEFAULT 1, u002du002d Drapeau boolu00e9enn created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMPn) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Exemple 2 : Logs d’accès
CREATE TABLE access_logs (n id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, u002du002d Fort volumen user_id INT UNSIGNED, u002du002d Mu00eame type que users.idn status_code SMALLINT UNSIGNED NOT NULL, u002du002d HTTP 200, 404, 500...n response_ms INT UNSIGNED, u002du002d Temps de ru00e9ponse en msn created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,n INDEX idx_user (user_id),n INDEX idx_created (created_at)n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Exemple 3 : Relevés de capteurs IoT
CREATE TABLE sensor_readings (n id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n device_id INT UNSIGNED NOT NULL,n temperature FLOAT, u002du002d La pru00e9cision du capteur suffitn humidity FLOAT, u002du002d Idemn latitude DOUBLE, u002du002d Le GPS nu00e9cessite haute pru00e9cisionn longitude DOUBLE, u002du002d Idemn battery_pct TINYINT UNSIGNED, u002du002d Batterie 0-100 %n recorded_at DATETIME(3) NOT NULL, u002du002d Pru00e9cision u00e0 la milliseconden INDEX idx_device_time (device_id, recorded_at)n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Les trois tables partagent un point commun : chaque colonne est définie avec le plus petit type adapté à son usage. Les IDs s’adaptent avec INT ou BIGINT selon les besoins, l’argent utilise DECIMAL, les mesures utilisent FLOAT/DOUBLE, et les drapeaux utilisent TINYINT. C’est à cela que ressemble un schéma bien conçu.
Résumé — Le choix du type est de l’ingénierie de performance
Choisir un type numérique SQL n’est pas qu’une décision de formatage. Cela affecte l’efficacité du stockage, la performance des index, la vitesse des requêtes, la précision des données et la scalabilité future — tout à la fois.
L’essentiel en quatre lignes :
- Si ça tient dans un entier, utilisez un type entier (le plus rapide, le plus petit, zéro erreur)
- INT pour la plupart des colonnes, BIGINT pour les logs à fort volume (le stockage double)
- DECIMAL pour l’argent — sans exception (les erreurs FLOAT sont dévastatrices en finance)
- FLOAT / DOUBLE pour la science et les mesures (vitesse et plage quand l’approximation convient)
Par-dessus tout, le principe directeur est : choisissez le plus petit type qui répond à vos besoins. Les types surdimensionnés gaspillent du stockage, réduisent l’efficacité du cache et ralentissent les requêtes. Les types sous-dimensionnés risquent le dépassement. Bien choisir implique d’estimer la nature de vos données (entier vs. décimal), la plage de valeurs, la tolérance aux erreurs et le taux de croissance sur la durée de vie du système.
La conception des types numériques est un travail ingrat, mais bien le faire dès le premier jour vous épargnera la dégradation des performances, le gonflement du stockage et les incidents de production à venir. Chaque fois que vous écrivez un CREATE TABLE, demandez-vous : « Ce type est-il vraiment le bon ? » Cette seule habitude élèvera la qualité de votre conception de base de données.
FAQ
Q. Quelle est la première question à se poser quand on hésite sur le type ?
R. Demandez-vous d’abord : « Cette valeur peut-elle être représentée comme un entier ? » Si oui, optez pour un type INT. Ensuite : « Est-ce que cela concerne de l’argent ? » Si oui, DECIMAL est la seule réponse. Tout le reste avec des décimales — températures, coordonnées, scores — oriente vers FLOAT ou DOUBLE. Suivez cette séquence et 95 % des décisions sont instantanées.
Q. Est-il difficile de migrer d’INT vers BIGINT après coup ?
R. La commande ALTER TABLE ... MODIFY COLUMN de MySQL peut changer le type, mais sur les grandes tables, elle verrouille la table pendant des minutes, voire des heures. Des outils comme pt-online-schema-change ou gh-ost effectuent la migration avec un temps d’arrêt quasi nul, mais ils nécessitent tout de même une planification soigneuse. Bien choisir le type dès le départ est toujours moins coûteux que de le corriger après coup.
Q. PostgreSQL ne supporte pas UNSIGNED — que faire ?
R. C’est exact. L’approche standard sous PostgreSQL est d’utiliser une contrainte CHECK (CHECK (id >= 0)) pour garantir des valeurs non négatives. Comme l’INT de PostgreSQL monte tout de même à ~2,1 milliards, c’est suffisant pour la plupart des charges de travail. Si vous avez réellement besoin de la plage de 4,2 milliards, passez à BIGINT.
Q. Quelle est la gravité réelle des erreurs d’arrondi de FLOAT ?
R. FLOAT (4 octets) offre environ 7 chiffres significatifs. Stockez 123456,789 en FLOAT et vous pourriez récupérer 123456,7890625. Pour les données de capteurs ou les mesures scientifiques — où l’instrument lui-même a une précision limitée — c’est négligeable. Pour les calculs financiers, cela signifie des factures décalées d’un centime et des totaux mensuels qui ne correspondent plus. La règle est simple : n’utilisez jamais FLOAT pour l’argent.
Q. DECIMAL est-il vraiment plus lent qu’INT ? De combien ?
R. Pour les requêtes lourdes en agrégation (SUM, AVG sur des millions de lignes), DECIMAL peut être 1,2 à 2 fois plus lent qu’INT. Pour les charges OLTP classiques — des SELECT et INSERT individuels — la différence est négligeable. Certaines équipes stockent les prix en centimes entiers (ex. 19,99 € → 1999) pour bénéficier de la vitesse d’INT, mais cela pose problème dès qu’il faut gérer le multi-devises ou des calculs en sous-centimes. Commencer avec DECIMAL est le pari le plus sûr à long terme.

Laisser un commentaire