Comment concevoir un système de numérotation qui maximise la vitesse, la scalabilité et la maintenabilité dans Dolibarr ERP/CRM
1. Introduction
Dolibarr est une solution open‑source d’ERP/CRM très modulaire, mais comme tout système de gestion, sa performance dépend fortement de la façon dont les données sont structurées et identifiées. La numérotation des enregistrements (factures, devis, commandes, tickets, etc.) n’est pas seulement une question esthétique ; elle a un impact direct sur :
- la rapidité des requêtes SQL (filtre, jointure, tri) – la capacité à partitionner ou à indexer efficacement les tables
- la lisibilité et la traçabilité des opérations pour les utilisateurs et les audits
Cet article détaille les principes fondamentaux d’une numérotation orientée performance dans Dolibarr, propose des modèles de schémas numériques, et donne des recommandations concrètes pour les implémenter sans perdre en fiabilité ou en conformité légale.
2. Principes de base à garder en tête
| Principe | Pourquoi c’est important | Impact sur la performance |
|---|---|---|
| Prévisibilité du format | Permet aux requêtes de filtrer rapidement par préfixe ou suffixe (ex. WHERE ref_facture LIKE 'FAC-%'). |
Réduction des scans de table, meilleure utilisation des index. |
| Séquence monotone (incremental) | Garantit l’unicité sans besoin de verrous lourds (SELECT + INSERT). | Moins de contention sur les séquences, inserts plus rapides. |
| Dimensionnement (longueur fixe) | Évite les variations de taille de champ qui fragmentent les index. | Index plus compacts → lectures moindres. |
| Séparation logique (préfixe fonctionnel) | Permet de segmenter les données par type, client, année, site, etc. | Partitionnement facile, requêtes plus ciblées. |
| Compatibilité légale | Certaines industries imposent des formats (ex. TVA, pays). | Pas de refonte majeure du processus de facturation. |
| Extensibilité | Possibilité d’ajouter des informations (ex. site, devise) sans changer la clé primaire. | Facilite la migration future. |
3. Modèle de numérotation recommandé
3.1 Schéma général : [Prefixe][Année][Sous‑séquence]
| Élément | Exemple | Rôle |
|---|---|---|
| Préfixe fonctionnel | FAC, DEV, COM, TIC |
Identifie le type d’objet. |
| Année (4 chiffres) | 2025 |
Permet un filtrage rapide par période et un partitionnement par année. |
| Sous‑séquence (6‑8 chiffres, zéro‑rempli) | 000001 |
Numéro incrémental au sein de l’année et du type. |
| Suffix optionnel (site / devise) | -FR, -DE |
Identifie un site ou une monnaie sans impacter la clé primaire. |
Exemple complet (facture) :
FAC2025-000001-FR
FAC→ type document (Facture)2025→ année courante000001→ première facture de l’année –-FR→ suffixe indiquant le site France (facultatif)
3.2 Variante « Chronologie globale » ( lorsqu’un préfixe n’est pas souhaité)
Dans certains cas on préfère un numéro global qui combiné année et séquence :
FAC2025-000001
- Pas de préfixe séparé, tout le numéro est unique.
- À utiliser si le nombre de types de documents est limité (ex. seulement factures et devis).
3.3 Indexation & contraintes
- Clé primaire : laisser le champ numéro complet (
ref_facture) comme clé primaire (ouidauto‑increment si vous avez besoin de performance pure). - Index Efficient : créer un index unique sur le préfixe + année + sous‑séquence (ex.
INDEX idx_fact_ref_prefixe_annee_seq (ref_facture(1,10))). - Contraintes de format : implémenter un CHECK ou une expression de validation pour s’assurer que le champ suit le pattern
^[A-Z]{3}\d{4}-\d{6}(-[A-Z]{2})?$.
4. Pourquoi cette architecture améliore la performance ?
4.1 Moins de scans de table
- Filtre par préfixe : La clause
WHERE ref_facture LIKE 'FAC2025-%'utilise un préfixe fixe qui s’appuie sur l’index le plus à gauche, ce qui permet au SGBD (MySQL, PostgreSQL, etc.) d’utiliser uniquement la partie indexée pour éliminer les lignes non concordantes. - Partitionnement par année : En créant une partition logique (ex.
PARTITION BY RANGE (year(ref_facture))), chaque nouvelle année crée une nouvelle partition. Les requêtes ciblant une année ne touchent qu’à une partition → moins d’E/S.
4.2 Concurrence réduite
- Séquence monotone : En utilisant une séquence auto‑incrément déclarée au niveau de la table (
AUTO_INCREMENTouSERIAL), chaque transaction incrémente un compteur unique, évitant les blocages de verrouillage (SELECT … FOR UPDATE). - Pas de génération de UUID : Les UUID (36 caractères) sont coûteux à générer et fragmentent les index. Un simple entier de 8 chiffres suffit lorsqu’on a un processus unique par année.
4.3 Maintainabilité & conformité
- Auditabilité : Un numéro lisible indique immédiatement le type, l’année et l’ordre de création. Les auditors peuvent retracer rapidement les actions.
- Rapports rapides : Les outils de BI ou les tableaux de bord peuvent regrouper par préfixe (ex. « toutes les factures 2025 ») sans besoin de transformation.
5. Implémentation pas à pas dans Dolibarr
5.1 Configurer le format d’un nouveau mode de numérotation
- Accéder à
Administration > Périodes→ créer une période (ex.2025-01-01à2025-12-31). -
Aller dans
Administration > Factures > Modèles de facture→ Modifier le modèleNuméro de facture. 3. Définir le modèle de libellé :{$SEED}+{YEAR}+{NUM}$SEED: préfixe choisi (ex.FAC).{YEAR}: année courante (4 chiffres).{NUM}: séquence incrémentale (6 chiffres, zéro‑rempli).
- Sauvegarder et tester sur un enregistrement fictif : la valeur affichée doit être du type
FAC2025-000001.
5.2 Ajuster la base de données (MySQL / MariaDB)
-- Exemple : Ajouter un index dédié
CREATE INDEX idx_facture_prefixe_annee_seq
ON llx_facture(ref_facture(1,10));
-- Partitionnement (MySQL >= 5.7)
ALTER TABLE llx_facturePARTITION BY RANGE (YEAR(ref_facture)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);
Note : Le partitionnement est optionnel mais fortement conseillé dès que le volume de factures dépasse 100 000 lignes par année.
5.3 Vérifier les performances
-
Explain analyze :
EXPLAIN ANALYZE
SELECT COUNT(*) FROM llx_facture WHERE ref_facture LIKE 'FAC2025-%'; - Temps de réponse : idéalement sous 5 ms sur un serveur de test avec 200 k factures.
- Monitorage : activer le
slow_query_logde MySQL pour détecter d’éventuels filtres supplémentaires qui auraient besoin d’un index supplémentaire.
5.4 Adapter les autres entités (devis, commandes, tickets)
Répéter les mêmes étapes en changeant le préfixe et le seed :
| Entité | Préfixe recommandé | Exemple de format |
|---|---|---|
| Devis | DEV |
DEV2025-000001 |
| Commande client | COM |
COM2025-000001 |
| Ticket support | TIC |
TIC2025-000001-FR |
Vous pouvez créer un tableau de correspondance dans Admin > Paramètres > Séries de numéros afin de gérer plusieurs séries en même temps.
6. Bonnes pratiques et astuces supplémentaires
| Astuce | Description | Avantages |
|---|---|---|
| Utiliser des formats à longueur fixe | 000001 au lieu de 1 pour la séquence. |
Index plus stable, tri lexicographique = ordre chronologique. |
| Préfixer également le client (si besoin de multi‑site) | Ajouter le code du site à la suite : FAC2025-000001-IT. |
Permet de filtrer directement par site sans jointure supplémentaire. |
| Batch‑insert de plusieurs enregistrements | Insérer en lot (ex. 100 devis) avec des séquences déjà calculées. | Réduit le nombre de round‑trips réseau, améliore le débit d’insertion. |
| Archiver les années précédentes | Exporter les partitions < 4 ans vers un table d’archive et les supprimer de la table active. | Garde les tables actives légères, améliore les scans de requêtes courantes. |
| Cache des séries déjà utilisées | Stocker la dernière séquence générée dans une table de métadonnées (llx_numbering_sessions). |
Évite les collisions lors de replication ou de restore de bases. |
| Tester en charge | Simuler 10 000 requêtes simultanées de création d’enregistrements. | Détecte les goulots d’étranglement avant la mise en production. |
7. Exemple complet d’une table : llx_facture
CREATE TABLE llx_facture (
rowid SERIAL PRIMARY KEY,
fk_client INT NOT NULL,
label VARCHAR(255),
date_gen DATE NOT NULL,
probis INT DEFAULT 0,
fk_currency INT DEFAULT 0,
total_fk FLOAT NOT NULL DEFAULT 0,
total_wat FLOAT DEFAULT 0,
total_excl_tax FLOAT NOT NULL DEFAULT 0,
total_inc_tax FLOAT DEFAULT 0,
ref_facture VARCHAR(30) NOT NULL UNIQUE -- <--- notre champ numéroté
);
-- Index dédié
CREATE INDEX idx_facture_ref_fixed
ON llx_facture (ref_facture(1,10));
-- Partitionnement (exemple MySQL)
ALTER TABLE llx_facture
PARTITION BY RANGE (YEAR(date_gen)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);
ref_factureest généré automatiquement par le système de numérotation de Dolibarr (configuration décrite à la section 5.1).
8. Conclusion
Une numérotation orientée performance dans Dolibarr n’est pas une fonctionnalité « magique », mais le résultat d’une combinaison de :
- Convention de format claire (préfixe, année, séquence)
- Séquençage monotone pour éviter les verrous lourds
- Indexation ciblée et éventuellement partitionnement par année
- Adaptation aux exigences légales et aux besoins de reporting
En suivant le modèle décrit ci‑dessus – PREFIXE[ANNÉE]-[NUMÉRO][-SUFFIXE] – vous bénéficiez d’une rapidité de requêtage supérieure (filtrage par préfixe ultra‑rapide), d’une maintenance simplifiée (ajout de champs ou de sites sans toucher à la structure principale) et d’une scalabilité qui pourra suivre la croissance de votre activité, que ce soit pour quelques milliers ou plusieurs millions d’enregistrements.
Prochaine étape : implémenter les changements dans un environnement de test, mesurer les améliorations avec
EXPLAIN ANALYZE, puis les pousser en production en suivant les bonnes pratiques d’audit et de sauvegarde.
Bibliographie & Ressources complémentaires
- Dolibarr Documentation – Numéro de facture : https://dolibarr.org/en_US/doc/faq/advanced
- MySQL Partitioning : https://dev.mysql.com/doc/refman/8.0/en/partitioning.html
- OPTIMIZING MySQL PERFORMANCE – Chapter 5, “Indexing Strategies” (O’Reilly)
- SQL Patterns – Using Prefixes for Fast Queries – Blog PostgreSQL, 2023 Bonne optimisation de vos numérotations ! 🎯