{"id":21018,"date":"2026-08-26T11:48:58","date_gmt":"2026-08-26T09:48:58","guid":{"rendered":"https:\/\/webhosting.de\/mysql-histograms-bessere-query-plaene-ohne-index-optimizer\/"},"modified":"2026-08-26T11:48:58","modified_gmt":"2026-08-26T09:48:58","slug":"histogrammes-mysql-de-meilleurs-plans-de-requetes-sans-optimiseur-dindex","status":"publish","type":"post","link":"https:\/\/webhosting.de\/fr\/mysql-histograms-bessere-query-plaene-ohne-index-optimizer\/","title":{"rendered":"Histogrammes MySQL \u2013 De meilleurs plans de requ\u00eate sans index"},"content":{"rendered":"<p><strong>Histogrammes MySQL<\/strong> fournissent \u00e0 l'optimiseur des donn\u00e9es de distribution r\u00e9elles, afin qu'il puisse estimer correctement les s\u00e9lectivit\u00e9s et g\u00e9n\u00e9rer des plans de requ\u00eate plus rapides \u2013 souvent m\u00eame sans index suppl\u00e9mentaire. Je vais vous montrer comment je configure et contr\u00f4le les histogrammes dans MySQL 8+ \u00e0 l\u2019aide de la commande ANALYZE TABLE, et comment je les utilise pour prendre de meilleures d\u00e9cisions concernant les jointures, les filtres et les balayages.<\/p>\n\n<h2>Points centraux<\/h2>\n<p><strong>Focale courte<\/strong>: Les points cl\u00e9s suivants indiquent les aspects auxquels je pr\u00eate particuli\u00e8rement attention lorsque j'utilise des histogrammes.<\/p>\n<ul>\n  <li><strong>S\u00e9lectivit\u00e9<\/strong> Au lieu de se fier \u00e0 son intuition : des estimations de cardinalit\u00e9 plus r\u00e9alistes<\/li>\n  <li><strong>Sans index<\/strong> plus rapide : meilleur choix de plan pour les distributions asym\u00e9triques<\/li>\n  <li><strong>types<\/strong> Comprendre : utiliser de mani\u00e8re cibl\u00e9e le singleton et l'Equi-Height<\/li>\n  <li><strong>Seaux<\/strong> g\u00e9rer : mettre en balance la suppression et les co\u00fbts li\u00e9s aux m\u00e9tadonn\u00e9es<\/li>\n  <li><strong>Soins<\/strong> \u00c0 surveiller : mettre \u00e0 jour, v\u00e9rifier, supprimer si n\u00e9cessaire<\/li>\n<\/ul>\n\n<h2>Pourquoi les histogrammes sans index sont-ils efficaces ?<\/h2>\n<p>J'utilise <strong>Histogrammes<\/strong>, car sinon l'optimiseur part souvent du principe que la distribution est uniforme et choisit donc de mauvais plans. Un histogramme repr\u00e9sente la <strong>R\u00e9partition des valeurs<\/strong> il effectue une approximation sur une colonne et fournit ainsi des estimations r\u00e9alistes de la s\u00e9lectivit\u00e9 pour des pr\u00e9dicats tels que =, &gt;, BETWEEN, IN ou IS NULL. L\u2019optimiseur d\u00e9cide alors s\u2019il est plus avantageux d\u2019utiliser un balayage d\u2019index par plage, un balayage de table ou une strat\u00e9gie de jointure avec boucles imbriqu\u00e9es. Si, par exemple, une condition ne concerne que 0,1 % des lignes, je privil\u00e9gie un acc\u00e8s cibl\u00e9 plut\u00f4t qu\u2019un balayage large. En revanche, si un filtre couvre la quasi-totalit\u00e9 des lignes, je renonce aux acc\u00e8s \u00e0 l\u2019index co\u00fbteux qui n\u2019apportent aucun avantage et j\u2019augmente ainsi la <strong>Efficacit\u00e9<\/strong> de chaque plan.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql-query-histograms-6793.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Types d'histogrammes dans MySQL 8.0<\/h2>\n<p>Je distingue deux <strong>types<\/strong>: Singleton et Equi-Height. Les histogrammes de type Singleton regroupent les valeurs uniques fr\u00e9quentes dans des tranches distinctes \u2013 une solution id\u00e9ale pour les colonnes comportant peu de cat\u00e9gories dominantes telles que \u201e actif \u201c, \u201e inactif \u201c ou \u201e archiv\u00e9 \u201c. Les histogrammes \u00ab Equi-Height \u00bb r\u00e9partissent la plage de valeurs de mani\u00e8re \u00e0 ce que chaque tranche contienne un nombre similaire de <strong>Lignes<\/strong> ; cela convient aux distributions continues ou irr\u00e9guli\u00e8res, telles que les prix, les horodatages ou les plages d'identifiants \u201e lacunaires \u201c. Ces deux variantes fournissent \u00e0 l'optimiseur des taux de correspondance plus pr\u00e9cis pour les filtres. Je choisis toujours le type en fonction des caract\u00e9ristiques des donn\u00e9es, et non selon mes pr\u00e9f\u00e9rences personnelles.<\/p>\n\n<h2>Principes techniques : contr\u00f4ler le choix du type de donn\u00e9es dans MySQL<\/h2>\n<p>C'est MySQL qui d\u00e9termine la <strong>Variante d'histogramme<\/strong> automatiquement en fonction de la r\u00e9partition des donn\u00e9es. Concr\u00e8tement, cela signifie que si le nombre de valeurs distinctes (NDV) est suffisamment faible par rapport au nombre de tranches, on obtient en fait un histogramme de type \u201e singleton \u201c ; dans le cas contraire, un histogramme de type \u00ab equi-height \u00bb est g\u00e9n\u00e9r\u00e9. Je \u00ab choisis \u00bb donc le type <em>indirect<\/em>, en d\u00e9finissant la colonne appropri\u00e9e et un nombre de tranches adapt\u00e9. Pour les colonnes comportant tr\u00e8s peu de cat\u00e9gories, mais celles-ci \u00e9tant tr\u00e8s dominantes, je d\u00e9finis d\u00e9lib\u00e9r\u00e9ment un petit nombre de buckets afin d\u2019obtenir une pr\u00e9cision de type \u00ab singleton \u00bb pour ces valeurs. Dans le cas de donn\u00e9es continues et finement r\u00e9parties, j\u2019augmente progressivement le nombre de buckets jusqu\u2019\u00e0 ce qu\u2019EXPLAIN affiche la <strong>S\u00e9lectivit\u00e9<\/strong> refl\u00e8te.<\/p>\n<p>Important : les histogrammes sont <strong>sur une seule colonne<\/strong>. Les d\u00e9pendances entre colonnes (par exemple \u00ab status \u00bb et \u00ab country \u00bb) ne peuvent pas \u00eatre repr\u00e9sent\u00e9es directement. Dans ce genre de cas, il est utile de cr\u00e9er un histogramme pour la colonne la plus s\u00e9lective et d'adapter l'ordre des jointures en cons\u00e9quence.<\/p>\n\n<h2>Bien choisir ses seaux<\/h2>\n<p>Par d\u00e9faut, MySQL utilise 100 <strong>Seaux<\/strong>, mais permet de d\u00e9finir une valeur comprise entre 1 et 1 024 via WITH N BUCKETS. Un nombre plus \u00e9lev\u00e9 de buckets augmente la r\u00e9solution, mais entra\u00eene \u00e9galement une augmentation des m\u00e9tadonn\u00e9es et de la charge de travail li\u00e9e \u00e0 l'analyse. Je commence g\u00e9n\u00e9ralement par une valeur prudente, j'\u00e9value l'impact \u00e0 l'aide de la commande EXPLAIN, puis j'augmente progressivement ce nombre si le plan semble toujours inadapt\u00e9. Lorsque les valeurs sont tr\u00e8s concentr\u00e9es (par exemple, 90 % pour un statut), quelques buckets suffisent souvent ; en cas de prix ou d\u2019horodatages tr\u00e8s dispers\u00e9s, il vaut mieux utiliser davantage de buckets. L\u2019objectif est d\u2019obtenir une <strong>Granularit\u00e9<\/strong>, ce qui a permis de r\u00e9duire sensiblement les erreurs d'appr\u00e9ciation sans alourdir inutilement la charge administrative.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql_histogramm_meeting_8123.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Exemple pratique : workflow avec ANALYZE TABLE<\/h2>\n<p>Je suis une ligne directrice claire <strong>Flux de travail<\/strong>: Je commence par identifier les colonnes qui apparaissent souvent dans les conditions WHERE ou JOIN et qui pr\u00e9sentent des distributions manifestement asym\u00e9triques. Ensuite, je g\u00e9n\u00e8re un histogramme \u00e0 l\u2019aide de la commande ANALYZE TABLE tbl UPDATE HISTOGRAM ON col WITH N BUCKETS ; puis je le v\u00e9rifie via INFORMATION_SCHEMA.COLUMN_STATISTICS. Apr\u00e8s des mouvements de donn\u00e9es, je rafra\u00eechis \u00e0 nouveau les statistiques avec ANALYZE TABLE. Si une statistique ne convient pas, je la supprime avec ANALYZE TABLE tbl DROP HISTOGRAM ON col;. Pour \u00e9valuer l'impact sur le plan d'ex\u00e9cution, je consulte <a href=\"https:\/\/webhosting.de\/fr\/interpreter-les-requetes-mysql-explain-et-analyze-optimisation-des-requetes\/\">Interpr\u00e9ter EXPLAIN ANALYZE<\/a> et ces estimations par rapport aux chiffres r\u00e9els <strong>Lignes<\/strong> \u00e0 partir de<\/p>\n\n<h2>Ordres concrets et contr\u00f4le<\/h2>\n<p>Je proc\u00e8de de mani\u00e8re reproductible, en suivant quelques \u00e9tapes claires, et je v\u00e9rifie les statistiques JSON g\u00e9n\u00e9r\u00e9es.<\/p>\n<pre><code>-- Cr\u00e9er des histogrammes sur des colonnes individuelles\nANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 32 BUCKETS;\nANALYZE TABLE orders UPDATE HISTOGRAM ON created_at WITH 128 BUCKETS;\n\n-- Plusieurs colonnes en une seule op\u00e9ration avec le m\u00eame nombre de compartiments\nANALYZE TABLE orders UPDATE HISTOGRAM ON status, payment_method WITH 64 BUCKETS;\n\n-- Supprimer des histogrammes de mani\u00e8re cibl\u00e9e\nANALYZE TABLE orders DROP HISTOGRAM ON status;\n<\/code><\/pre>\n<pre><code>-- V\u00e9rification visuelle des statistiques\nSELECT\n  SCHEMA_NAME, TABLE_NAME, COLUMN_NAME,\n  JSON_PRETTY(HISTOGRAM) AS histogram\nFROM INFORMATION_SCHEMA.COLUMN_STATISTICS\nWHERE SCHEMA_NAME = DATABASE()\n  AND TABLE_NAME = 'orders'\n  AND COLUMN_NAME IN ('status','created_at');\n<\/code><\/pre>\n<p>J'\u00e9value imm\u00e9diatement l'impact \u00e0 l'aide de la commande EXPLAIN ANALYZE :<\/p>\n<pre><code>EXPLAIN ANALYZE\nSELECT *\nFROM orders\nWHERE status = 'canceled'\n  AND created_at &gt;= NOW() - INTERVAL 7 DAY;\n<\/code><\/pre>\n<p>L'estimation s'am\u00e9liore-t-elle ? <strong>lignes<\/strong> Si l'on constate une diff\u00e9rence notable et que le plan passe, par exemple, d'un \u00ab Full Scan \u00bb \u00e0 un \u00ab Index-Range-Scan \u00bb ou modifie l'ordre des jointures, cela signifie que la mesure a port\u00e9 ses fruits. Si l'\u00e9cart reste important, j'augmente ou je r\u00e9duis le nombre de buckets, puis je compare \u00e0 nouveau.<\/p>\n\n<h2>Exemple : statut des commandes et valeurs rares<\/h2>\n<p>Dans un tableau \u201e orders \u201c, le statut \u201e completed \u201c pr\u00e9domine souvent, tandis que \u201e pending \u201c est assez fr\u00e9quent et \u00ab canceled \u00bb tr\u00e8s rare ; ceci <strong>d\u00e9s\u00e9quilibre<\/strong> sans histogramme, cela conduit facilement \u00e0 des s\u00e9lectivit\u00e9s erron\u00e9es. Si une API interroge \u201e canceled \u201c, l'optimiseur peut choisir \u00e0 tort un balayage complet de la table, alors qu'un acc\u00e8s par index plus pr\u00e9cis suffirait. Gr\u00e2ce \u00e0 un histogramme singleton, MySQL d\u00e9tecte que \u201e canceled \u201c ne repr\u00e9sente qu\u2019une infime partie et opte pour un balayage d\u2019intervalle d\u2019index ou optimise l\u2019ordre des jointures. Cela r\u00e9duit la latence, et je n\u2019ai pas besoin d\u2019un index suppl\u00e9mentaire pour chaque <strong>Variante<\/strong> d'un filtre. Dans les tableaux de bord dot\u00e9s de SLO stricts, cette correction apporte souvent des gains de r\u00e9activit\u00e9 notables.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql-histograms-server-room-2973.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>S\u00e9ries chronologiques et horodatages<\/h2>\n<p>Dans le cas des s\u00e9ries chronologiques, il y a beaucoup de <strong>Acc\u00e8s<\/strong> sur des donn\u00e9es r\u00e9centes ; les plages horaires plus anciennes restent g\u00e9n\u00e9ralement inactives. Un histogramme \u00ab Equi-Height \u00bb sur les colonnes `created_at` ou `updated_at` permet de distinguer les plages horaires tr\u00e8s fr\u00e9quent\u00e9es de celles qui le sont rarement. L\u2019optimiseur \u00e9value alors correctement s\u2019il est judicieux d\u2019effectuer un balayage par plage (Range Scan) ou si un balayage de table (Table Scan) permet d\u2019atteindre plus rapidement l\u2019objectif. Je constate notamment, lors de filtrages temporels partiels sur de grandes tables, des changements de plan significatifs et une r\u00e9duction des co\u00fbts d\u2019E\/S. Je consid\u00e8re que la <strong>Statistiques<\/strong> ici, les mises \u00e0 jour sont plus fr\u00e9quentes, car les priorit\u00e9s \u00e9voluent en fonction de l'activit\u00e9 quotidienne.<\/p>\n\n<h2>Partitions, types de donn\u00e9es et collations<\/h2>\n<p>Je examine la r\u00e9partition des donn\u00e9es sur des tables partitionn\u00e9es <strong>sur toutes les partitions<\/strong>. Des \u00e9carts importants (par exemple, sur plusieurs mois) peuvent lisser les histogrammes globaux. Si certaines partitions sont extr\u00eamement s\u00e9lectives ou extr\u00eamement larges, je v\u00e9rifie \u00e9galement, \u00e0 l'aide de filtres de \u00ab partition pruning \u00bb dans la clause WHERE, si la qualit\u00e9 du plan reste satisfaisante. Dans l\u2019ensemble, je veille \u00e0 formuler les filtres de mani\u00e8re \u00e0 ce que MySQL identifie les partitions d\u00e8s le d\u00e9but <strong>exclure<\/strong> peut.<\/p>\n<p>Les histogrammes fonctionnent mieux avec des types de donn\u00e9es scalaires et comparables (nombres, dates\/heures, VARCHAR\/CHAR avec une collation appropri\u00e9e). Dans le cas de <strong>Donn\u00e9es LOB\/JSON<\/strong> je mise plut\u00f4t sur <em>Colonnes g\u00e9n\u00e9r\u00e9es<\/em> avec des valeurs extraites et typ\u00e9es, et les accompagne, si n\u00e9cessaire, d'histogrammes ou d'indices. Pour les cha\u00eenes de caract\u00e8res, la <strong>collation<\/strong> la logique de comparaison ; selon la collation, des valeurs peuvent co\u00efncider (par exemple, en tenant compte de la casse). Je veille \u00e0 ce que la collation soit coh\u00e9rente avec les requ\u00eates afin d'obtenir des s\u00e9lectivit\u00e9s r\u00e9alistes.<\/p>\n\n<h2>Limites et erreurs<\/h2>\n<p>Les histogrammes \u00e9valuent principalement les colonnes individuelles avec <strong>Constantes<\/strong> C'est vrai ; ils ne refl\u00e8tent que de mani\u00e8re limit\u00e9e les d\u00e9pendances entre plusieurs colonnes. Ils atteignent leurs limites lorsque les colonnes sont fortement corr\u00e9l\u00e9es ou qu'il s'agit de param\u00e8tres dynamiques (par exemple, renseign\u00e9s par l'application). Les champs bool\u00e9ens ou les colonnes pr\u00e9sentant une distribution quasi uniforme tirent rarement profit de statistiques suppl\u00e9mentaires. Un nombre trop \u00e9lev\u00e9 de tranches et une maintenance excessive peuvent, \u00e0 leur tour, allonger le temps consacr\u00e9 \u00e0 l\u2019administration et \u00e0 l\u2019analyse. C\u2019est pourquoi j\u2019utilise les histogrammes de mani\u00e8re cibl\u00e9e et je v\u00e9rifie r\u00e9guli\u00e8rement la <strong>Effet<\/strong> sur des mod\u00e8les r\u00e9els.<\/p>\n\n<h2>V\u00e9rification et mise \u00e0 jour de l'optimiseur<\/h2>\n<p>Je v\u00e9rifie le <strong>Utilisation<\/strong> des histogrammes via ANALYZE TABLE et des options pertinentes de l'optimiseur, afin que le planificateur utilise les statistiques de mani\u00e8re pertinente. Dans les syst\u00e8mes tr\u00e8s sollicit\u00e9s, je planifie la mise \u00e0 jour pendant les p\u00e9riodes creuses ou par lots apr\u00e8s des chargements importants. Avant et apr\u00e8s, je compare les r\u00e9sultats d\u2019EXPLAIN et d\u2019EXPLAIN ANALYZE afin d\u2019\u00e9valuer les modifications apport\u00e9es \u00e0 l\u2019ordre des jointures, aux \u00e9tapes de filtrage et aux mod\u00e8les de co\u00fbts. En cas d\u2019effets n\u00e9gatifs, je r\u00e9agis imm\u00e9diatement et je r\u00e9tablis la statistique pr\u00e9c\u00e9dente. Pour un contr\u00f4le plus approfondi de la <a href=\"https:\/\/webhosting.de\/fr\/mysql-optimizer-query-hosting-optimisation-serverboost\/\">Options de l'optimiseur<\/a> je veille \u00e0 ce que les d\u00e9pendances avec d'autres statistiques ne donnent pas lieu, \u00e0 mon insu, \u00e0 des <strong>Hypoth\u00e8ses<\/strong> produire.<\/p>\n\n<h2>Surveillance, protection contre la r\u00e9gression et guide op\u00e9rationnel<\/h2>\n<p>Je me fabrique un mod\u00e8le l\u00e9ger <strong>Guide tactique<\/strong> pour l'exploitation en production :<\/p>\n<ul>\n  <li>D\u00e9finir une base de r\u00e9f\u00e9rence : avant d'effectuer des modifications, ex\u00e9cuter EXPLAIN ANALYZE, noter la dur\u00e9e d'ex\u00e9cution, le nombre de \u201e lignes examin\u00e9es \u201c et le compteur du gestionnaire.<\/li>\n  <li>Cr\u00e9er\/modifier un histogramme : cibler les colonnes de filtrage, utiliser des tranches conservatrices.<\/li>\n  <li>Mesurer imm\u00e9diatement apr\u00e8s : plan, nombre de lignes estim\u00e9 par rapport au nombre r\u00e9el ; un \u00e9cart sup\u00e9rieur \u00e0 10 est pour moi un signal d'alerte.<\/li>\n  <li>R\u00e9glage fin : augmenter\/diminuer le nombre de tranches ; si n\u00e9cessaire, modifier l'ordre des filtres dans la requ\u00eate.<\/li>\n  <li>Pr\u00e9parer une restauration : ex\u00e9cuter la commande DROP HISTOGRAM si les latences augmentent.<\/li>\n  <li>Automatisation : ex\u00e9cution de la commande ANALYZE apr\u00e8s les chargements ETL ou les vagues importantes d'op\u00e9rations DML, pendant les fen\u00eatres de maintenance.<\/li>\n<\/ul>\n<p>Pour analyser les causes, j'utilise <strong>Traces de l'optimiseur<\/strong> et EXPLAIN ANALYZE pour v\u00e9rifier si le planificateur, sur la base des histogrammes, met bien en avant la table s\u00e9lective appropri\u00e9e. Pour les tests A\/B, je fixe \u00e0 titre d'essai l'ordre des jointures (STRAIGHT_JOIN) ou j'impose\/interdis l'utilisation de certains index afin d'\u00e9valuer de mani\u00e8re isol\u00e9e l'effet des statistiques.<\/p>\n<p>D'un point de vue organisationnel, un bref <strong>Journal des changements<\/strong> Par tableau : colonne, nombre de tranches, date et heure, valeurs mesur\u00e9es avant\/apr\u00e8s. Cela facilite les corrections ult\u00e9rieures et \u00e9vite les interactions ambigu\u00ebs.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql_histogram_techoffice_4829.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Aspects op\u00e9rationnels : blocages, co\u00fbts, portabilit\u00e9<\/h2>\n<p>ANALYZE TABLE effectue une <strong>Blocage des m\u00e9tadonn\u00e9es<\/strong> sur la table, mais ne bloque pas de mani\u00e8re permanente les op\u00e9rations habituelles de lecture\/\u00e9criture. Pour les tr\u00e8s grandes tables, je pr\u00e9vois suffisamment de temps ; la g\u00e9n\u00e9ration d\u2019histogrammes fonctionne par \u00e9chantillonnage et est limit\u00e9e par la m\u00e9moire (mot-cl\u00e9 : m\u00e9moire interne pour le calcul). L'espace requis par les statistiques elles-m\u00eames reste mod\u00e9r\u00e9 : quelques dizaines \u00e0 quelques centaines de kilo-octets par colonne comportant 100 \u00e0 256 compartiments constituent une valeur indicative r\u00e9aliste. Au total, je fais tout de m\u00eame le calcul, car de nombreuses colonnes multipli\u00e9es par de nombreuses tables donnent <strong>m\u00e9tadonn\u00e9es visibles<\/strong>.<\/p>\n<p>\u00c0 l'adresse suivante : <strong>Dumps logiques<\/strong> (mysqldump) les histogrammes ne sont pas inclus dans les donn\u00e9es ; apr\u00e8s une restauration, je les recr\u00e9e de mani\u00e8re cibl\u00e9e. Lors d\u2019une mise \u00e0 niveau sur place, ils sont conserv\u00e9s. C\u00f4t\u00e9 serveur, j\u2019ai besoin de privil\u00e8ges suffisants pour ex\u00e9cuter ANALYZE TABLE sur les objets concern\u00e9s ; dans les environnements strictement r\u00e9glement\u00e9s, j\u2019int\u00e8gre cette t\u00e2che dans des pipelines de maintenance.<\/p>\n\n<h2>Quand les histogrammes ne servent \u00e0 rien<\/h2>\n<p>Je m'\u00e9pargne <strong>Histogrammes<\/strong> sur les colonnes qui contiennent tr\u00e8s peu de valeurs et qui sont de toute fa\u00e7on bien estim\u00e9es. M\u00eame lorsque l'un des bons index couvre d\u00e9j\u00e0 des ensembles de r\u00e9sultats minimaux, un histogramme apporte rarement un gain suppl\u00e9mentaire. Les distributions uniformes ne n\u00e9cessitent pas une granularit\u00e9 pouss\u00e9e. Dans les syst\u00e8mes hautement dynamiques et \u00e0 forte intensit\u00e9 d\u2019\u00e9criture, la maintenance peut g\u00e9n\u00e9rer une charge inutile si je la lance trop fr\u00e9quemment. Dans de telles situations, j\u2019utilise la <strong>\u00c9nergie<\/strong> plut\u00f4t dans les strat\u00e9gies d'indexation, la conception des requ\u00eates et la mise en cache.<\/p>\n\n<h2>Aide-m\u00e9moire sous forme de tableau<\/h2>\n<p>J'utilise le suivant <strong>Vue d'ensemble<\/strong> pour prendre rapidement des d\u00e9cisions : quel type d'histogramme choisir, comment d\u00e9finir les tranches (buckets) et quels sont les co\u00fbts associ\u00e9s. Ce tableau sert d\u2019aide-m\u00e9moire lors de l\u2019analyse des requ\u00eates probl\u00e9matiques. Je le mets \u00e0 jour en fonction des enseignements tir\u00e9s d\u2019EXPLAIN ANALYZE et des m\u00e9triques de production. Ce faisant, je tiens compte du fait que les distributions des donn\u00e9es \u00e9voluent et que les hypoth\u00e8ses historiques deviennent obsol\u00e8tes. L\u2019essentiel reste de <strong>qualit\u00e9 de la planification<\/strong> \u00e0 confirmer par des mesures r\u00e9elles.<\/p>\n<table>\n  <thead>\n    <tr>\n      <th>Aspect<\/th>\n      <th>Recommandation<\/th>\n      <th>Avantages<\/th>\n      <th>compromis<\/th>\n      <th>Exemple<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>Type<\/td>\n      <td>Singleton en pr\u00e9sence de quelques valeurs dominantes<\/td>\n      <td>Taux de r\u00e9ussite pr\u00e9cis pour les cat\u00e9gories courantes<\/td>\n      <td>Peu utile pour les zones continues<\/td>\n      <td>statut_de_la_commande<\/td>\n    <\/tr>\n    <tr>\n      <td>Type<\/td>\n      <td>Equi-Height pour des donn\u00e9es continues d\u00e9form\u00e9es<\/td>\n      <td>Meilleure estimation sur l'ensemble de la plage de valeurs<\/td>\n      <td>Davantage de m\u00e9tadonn\u00e9es lorsque le nombre de compartiments est \u00e9lev\u00e9<\/td>\n      <td>created_at, price<\/td>\n    <\/tr>\n    <tr>\n      <td>Seaux<\/td>\n      <td>Commencer \u00e0 100, puis ajuster<\/td>\n      <td>Une r\u00e9solution \u00e9quilibr\u00e9e<\/td>\n      <td>Charge d'analyse et de stockage plus \u00e9lev\u00e9e entre 512 et 1 024<\/td>\n      <td>AVEC 100 SEAUX<\/td>\n    <\/tr>\n    <tr>\n      <td>Soins<\/td>\n      <td>Apr\u00e8s des modifications importantes des donn\u00e9es, ex\u00e9cutez la commande ANALYZE<\/td>\n      <td>S\u00e9lectivit\u00e9s actuelles<\/td>\n      <td>Planifier une fen\u00eatre de maintenance<\/td>\n      <td>ANALYZE TABLE \u2026 UPDATE HISTOGRAM<\/td>\n    <\/tr>\n    <tr>\n      <td>Contr\u00f4le<\/td>\n      <td>V\u00e9rifier via COLUMN_STATISTICS<\/td>\n      <td>Transparence et audit<\/td>\n      <td>Interpr\u00e9tation JSON requise<\/td>\n      <td>INFORMATION_SCHEMA.COLUMN_STATISTICS<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n<h2>Int\u00e9gration dans le projet global de tuning<\/h2>\n<p>Je traite <strong>Histogrammes<\/strong> en tant qu'\u00e9l\u00e9ment constitutif, au m\u00eame titre que les index, la conception des requ\u00eates, la mise en cache et les param\u00e8tres mat\u00e9riels. Souvent, un bon histogramme modifie l'ordre des jointures, r\u00e9duit les E\/S et garantit des temps de r\u00e9ponse constants. Cela ne remplace toutefois pas des strat\u00e9gies d'indexation bien con\u00e7ues ni un sch\u00e9ma efficace. Ceux qui examinent de plus pr\u00e8s les d\u00e9cisions de planification tirent profit de <a href=\"https:\/\/webhosting.de\/fr\/base-de-donnees-plans-dexecution-des-requetes-hebergement-optimisation-des-performances-insights\/\">Comprendre les plans d'ex\u00e9cution<\/a> et compare les mod\u00e8les de co\u00fbts aux dur\u00e9es r\u00e9elles. Je v\u00e9rifie r\u00e9guli\u00e8rement si les <strong>Charges de travail<\/strong> correspondent encore aux statistiques ou s'il faut proc\u00e9der \u00e0 des ajustements.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql-queryplanung-8216.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Sc\u00e9narios de joint avanc\u00e9s<\/h2>\n<p>Les histogrammes s'av\u00e8rent particuli\u00e8rement utiles lorsque plusieurs tableaux comportant des filtres sont impliqu\u00e9s. Exemple :<\/p>\n<pre><code>SELECT o.id, o.amount\nFROM users u\nJOIN orders o ON o.user_id = u.id\nWHERE u.country = 'DE'\n  AND o.status = 'canceled'\n  AND o.created_at &gt;= NOW() - INTERVAL 30 DAY;\n<\/code><\/pre>\n<p>Sans histogrammes, l'optimiseur risque de sous-estimer la s\u00e9lectivit\u00e9 de `o.status=\u2019canceled\u2018` ou de surestimer la proportion d'utilisateurs allemands. Avec un histogramme sur <em>et pays<\/em> et <em>sans statut<\/em> (le cas \u00e9ch\u00e9ant, \u00e9galement sur <em>o.created_at<\/em>), le planificateur se rend g\u00e9n\u00e9ralement compte que cette combinaison est extr\u00eamement s\u00e9lective. Dans la pratique, je constate alors que MySQL d\u00e9termine d\u2019abord le sous-ensemble le plus petit (par exemple via un index sur users(country) ou orders(status, created_at)) et n\u2019effectue la jointure qu\u2019ensuite \u2013 au lieu de parcourir la grande table. Cela permet d\u2019\u00e9conomiser des op\u00e9rations d\u2019E\/S, de la m\u00e9moire tampon et de la puissance CPU, tout en stabilisant la latence, m\u00eame sous charge.<\/p>\n<p>Parce que les histogrammes ne sont que <strong>sur une seule colonne<\/strong> les strat\u00e9gies d'index restent importantes : un index composite sur (status, created_at) peut acc\u00e9l\u00e9rer encore davantage le balayage de plage. L'histogramme sert ici principalement \u00e0 garantir que l'optimiseur <em>Strat\u00e9gie<\/em> qu'il juge globalement avantageux.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql_histogram_desk_4721.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>R\u00e9sum\u00e9 pour la pratique<\/h2>\n<p>Je mets <strong>MySQL<\/strong>- J'utilise des histogrammes lorsque l'optimiseur se trompe en se basant sur les statistiques par d\u00e9faut et que des distributions asym\u00e9triques g\u00e9n\u00e8rent des plans d'ex\u00e9cution erron\u00e9s. Avec ANALYZE TABLE, je cr\u00e9e, mets \u00e0 jour et supprime de mani\u00e8re cibl\u00e9e les statistiques sur les colonnes qui pr\u00e9dominent dans les filtres et les jointures. Je choisis entre \u00ab Singleton \u00bb et \u00ab Equi-Height \u00bb en fonction des donn\u00e9es, et je calibre le nombre de compartiments \u00e0 l\u2019aide de mesures. Gr\u00e2ce \u00e0 EXPLAIN ANALYZE, je v\u00e9rifie si l\u2019ordre des jointures, la position des filtres et les balayages \u00e9voluent comme souhait\u00e9. C\u2019est ainsi que j\u2019obtiens, avec peu <strong>Overhead<\/strong> des requ\u00eates nettement plus rapides \u2013 souvent sans index suppl\u00e9mentaires.<\/p>","protected":false},"excerpt":{"rendered":"<p>D\u00e9couvrez comment les histogrammes MySQL fournissent \u00e0 l'optimiseur des statistiques pr\u00e9cises, permettent d'\u00e9laborer de meilleurs plans de requ\u00eate et am\u00e9liorent consid\u00e9rablement l'optimisation de vos requ\u00eates SQL sans avoir recours \u00e0 des index suppl\u00e9mentaires.<\/p>","protected":false},"author":1,"featured_media":21011,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[781],"tags":[],"class_list":["post-21018","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-datenbanken-administration-anleitungen"],"acf":[],"_wp_attached_file":null,"_wp_attachment_metadata":null,"litespeed-optimize-size":null,"litespeed-optimize-set":null,"_elementor_source_image_hash":null,"_wp_attachment_image_alt":null,"stockpack_author_name":null,"stockpack_author_url":null,"stockpack_provider":null,"stockpack_image_url":null,"stockpack_license":null,"stockpack_license_url":null,"stockpack_modification":null,"color":null,"original_id":null,"original_url":null,"original_link":null,"unsplash_location":null,"unsplash_sponsor":null,"unsplash_exif":null,"unsplash_attachment_metadata":null,"_elementor_is_screenshot":null,"surfer_file_name":null,"surfer_file_original_url":null,"envato_tk_source_kit":null,"envato_tk_source_index":null,"envato_tk_manifest":null,"envato_tk_folder_name":null,"envato_tk_builder":null,"envato_elements_download_event":null,"_menu_item_type":null,"_menu_item_menu_item_parent":null,"_menu_item_object_id":null,"_menu_item_object":null,"_menu_item_target":null,"_menu_item_classes":null,"_menu_item_xfn":null,"_menu_item_url":null,"_trp_menu_languages":null,"rank_math_primary_category":null,"rank_math_title":null,"inline_featured_image":null,"_yoast_wpseo_primary_category":null,"rank_math_schema_blogposting":null,"rank_math_schema_videoobject":null,"_oembed_049c719bc4a9f89deaead66a7da9fddc":null,"_oembed_time_049c719bc4a9f89deaead66a7da9fddc":null,"_yoast_wpseo_focuskw":null,"_yoast_wpseo_linkdex":null,"_oembed_27e3473bf8bec795fbeb3a9d38489348":null,"_oembed_c3b0f6959478faf92a1f343d8f96b19e":null,"_trp_translated_slug_en_us":null,"_wp_desired_post_slug":null,"_yoast_wpseo_title":null,"tldname":null,"tldpreis":null,"tldrubrik":null,"tldpolicylink":null,"tldsize":null,"tldregistrierungsdauer":null,"tldtransfer":null,"tldwhoisprivacy":null,"tldregistrarchange":null,"tldregistrantchange":null,"tldwhoisupdate":null,"tldnameserverupdate":null,"tlddeletesofort":null,"tlddeleteexpire":null,"tldumlaute":null,"tldrestore":null,"tldsubcategory":null,"tldbildname":null,"tldbildurl":null,"tldclean":null,"tldcategory":null,"tldpolicy":null,"tldbesonderheiten":null,"tld_bedeutung":null,"_oembed_d167040d816d8f94c072940c8009f5f8":null,"_oembed_b0a0fa59ef14f8870da2c63f2027d064":null,"_oembed_4792fa4dfb2a8f09ab950a73b7f313ba":null,"_oembed_33ceb1fe54a8ab775d9410abf699878d":null,"_oembed_fd7014d14d919b45ec004937c0db9335":null,"_oembed_21a029d076783ec3e8042698c351bd7e":null,"_oembed_be5ea8a0c7b18e658f08cc571a909452":null,"_oembed_a9ca7a298b19f9b48ec5914e010294d2":null,"_oembed_f8db6b27d08a2bb1f920e7647808899a":null,"_oembed_168ebde5096e77d8a89326519af9e022":null,"_oembed_cdb76f1b345b42743edfe25481b6f98f":null,"_oembed_87b0613611ae54e86e8864265404b0a1":null,"_oembed_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_oembed_time_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_tldname":null,"_tldclean":null,"_tldpreis":null,"_tldcategory":null,"_tldsubcategory":null,"_tldpolicy":null,"_tldpolicylink":null,"_tldsize":null,"_tldregistrierungsdauer":null,"_tldtransfer":null,"_tldwhoisprivacy":null,"_tldregistrarchange":null,"_tldregistrantchange":null,"_tldwhoisupdate":null,"_tldnameserverupdate":null,"_tlddeletesofort":null,"_tlddeleteexpire":null,"_tldumlaute":null,"_tldrestore":null,"_tldbildname":null,"_tldbildurl":null,"_tld_bedeutung":null,"_tldbesonderheiten":null,"_oembed_ad96e4112edb9f8ffa35731d4098bc6b":null,"_oembed_8357e2b8a2575c74ed5978f262a10126":null,"_oembed_3d5fea5103dd0d22ec5d6a33eff7f863":null,"_eael_widget_elements":null,"_oembed_0d8a206f09633e3d62b95a15a4dd0487":null,"_oembed_time_0d8a206f09633e3d62b95a15a4dd0487":null,"_aioseo_description":null,"_eb_attr":null,"_eb_data_table":null,"_oembed_819a879e7da16dd629cfd15a97334c8a":null,"_oembed_time_819a879e7da16dd629cfd15a97334c8a":null,"_acf_changed":null,"_wpcode_auto_insert":null,"_edit_last":null,"_edit_lock":null,"_oembed_e7b913c6c84084ed9702cb4feb012ddd":null,"_oembed_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_time_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_03514b67990db061d7c4672de26dc514":null,"_oembed_time_03514b67990db061d7c4672de26dc514":null,"rank_math_news_sitemap_robots":null,"rank_math_robots":null,"_eael_post_view_count":"108","_trp_automatically_translated_slug_ru_ru":null,"_trp_automatically_translated_slug_et":null,"_trp_automatically_translated_slug_lv":null,"_trp_automatically_translated_slug_fr_fr":null,"_trp_automatically_translated_slug_en_us":null,"_wp_old_slug":null,"_trp_automatically_translated_slug_da_dk":null,"_trp_automatically_translated_slug_pl_pl":null,"_trp_automatically_translated_slug_es_es":null,"_trp_automatically_translated_slug_hu_hu":null,"_trp_automatically_translated_slug_fi":null,"_trp_automatically_translated_slug_ja":null,"_trp_automatically_translated_slug_lt_lt":null,"_elementor_edit_mode":null,"_elementor_template_type":null,"_elementor_version":null,"_elementor_pro_version":null,"_wp_page_template":null,"_elementor_page_settings":null,"_elementor_data":null,"_elementor_css":null,"_elementor_conditions":null,"_happyaddons_elements_cache":null,"_oembed_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_time_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_time_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_59808117857ddf57e478a31d79f76e4d":null,"_oembed_time_59808117857ddf57e478a31d79f76e4d":null,"_oembed_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_time_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_81002f7ee3604f645db4ebcfd1912acf":null,"_oembed_time_81002f7ee3604f645db4ebcfd1912acf":null,"_elementor_screenshot":null,"_oembed_7ea3429961cf98fa85da9747683af827":null,"_oembed_time_7ea3429961cf98fa85da9747683af827":null,"_elementor_controls_usage":null,"_elementor_page_assets":[],"_elementor_screenshot_failed":null,"theplus_transient_widgets":null,"_eael_custom_js":null,"_wp_old_date":null,"_trp_automatically_translated_slug_it_it":null,"_trp_automatically_translated_slug_pt_pt":null,"_trp_automatically_translated_slug_zh_cn":null,"_trp_automatically_translated_slug_nl_nl":null,"_trp_automatically_translated_slug_pt_br":null,"_trp_automatically_translated_slug_sv_se":null,"rank_math_analytic_object_id":null,"rank_math_internal_links_processed":"1","_trp_automatically_translated_slug_ro_ro":null,"_trp_automatically_translated_slug_sk_sk":null,"_trp_automatically_translated_slug_bg_bg":null,"_trp_automatically_translated_slug_sl_si":null,"litespeed_vpi_list":null,"litespeed_vpi_list_mobile":null,"rank_math_seo_score":null,"rank_math_contentai_score":null,"ilj_limitincominglinks":null,"ilj_maxincominglinks":null,"ilj_limitoutgoinglinks":null,"ilj_maxoutgoinglinks":null,"ilj_limitlinksperparagraph":null,"ilj_linksperparagraph":null,"ilj_blacklistdefinition":null,"ilj_linkdefinition":null,"_eb_reusable_block_ids":null,"rank_math_focus_keyword":"MySQL Histograms","rank_math_og_content_image":null,"_yoast_wpseo_metadesc":null,"_yoast_wpseo_content_score":null,"_yoast_wpseo_focuskeywords":null,"_yoast_wpseo_keywordsynonyms":null,"_yoast_wpseo_estimated-reading-time-minutes":null,"rank_math_description":null,"surfer_last_post_update":null,"surfer_last_post_update_direction":null,"surfer_keywords":null,"surfer_location":null,"surfer_draft_id":null,"surfer_permalink_hash":null,"surfer_scrape_ready":null,"_thumbnail_id":"21011","footnotes":null,"_links":{"self":[{"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/posts\/21018","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/comments?post=21018"}],"version-history":[{"count":0,"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/posts\/21018\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/media\/21011"}],"wp:attachment":[{"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/media?parent=21018"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/categories?post=21018"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webhosting.de\/fr\/wp-json\/wp\/v2\/tags?post=21018"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}