{"id":549,"date":"2013-06-05T15:13:17","date_gmt":"2013-06-05T13:13:17","guid":{"rendered":"http:\/\/www.lafabriquedecode.com\/blog\/?p=549"},"modified":"2013-06-05T15:13:17","modified_gmt":"2013-06-05T13:13:17","slug":"mysql-max","status":"publish","type":"post","link":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/","title":{"rendered":"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d&rsquo;un champ"},"content":{"rendered":"<p>Si vous lisez r\u00e9guli\u00e8rement les billets de ce blog (ce que j&rsquo;esp\u00e8re secr\u00e8tement), vous savez que j&rsquo;essaie dans la mesure du possible de parler de choses qui servent au quotidien \u00e0 la fois pour les d\u00e9veloppeurs Web utilisant PHP mais aussi pour les personnes qui travaillent avec des bases de donn\u00e9es (relationnelles ou pas). C&rsquo;est ainsi qu&rsquo;aujourd&rsquo;hui nous allons nous focaliser sur un type de requ\u00eate relativement souvent utilis\u00e9 et qui a pour but de faire \u00ab\u00a0remonter\u00a0\u00bb la ligne (ou les lignes) contenant la plus grande valeur d&rsquo;un champ ! C&rsquo;est parti ! Amusons-nous avec nos joyeux \u00e9l\u00e8ves !<\/p>\n<div id=\"attachment_564\" style=\"width: 253px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/06\/happy-graduate.jpg\"><img aria-describedby=\"caption-attachment-564\" loading=\"lazy\" src=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/06\/happy-graduate.jpg\" alt=\"Voil\u00e0 un \u00e9l\u00e8ve joyeux !\" width=\"243\" height=\"326\" class=\"size-full wp-image-564\" srcset=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/06\/happy-graduate.jpg 243w, http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/06\/happy-graduate-223x300.jpg 223w\" sizes=\"(max-width: 243px) 100vw, 243px\" \/><\/a><p id=\"caption-attachment-564\" class=\"wp-caption-text\">Voil\u00e0 un \u00e9l\u00e8ve joyeux (j&rsquo;aimerais qu&rsquo;ils soient tous ainsi) !<\/p><\/div>\n<h1>Notre jeu de donn\u00e9es<\/h1>\n<p>Soit la table eleves :<\/p>\n<pre>mysql&gt; select * from eleves;\r\n+----+-----------+------------+------+\r\n| id | nom       | prenom     | note |\r\n+----+-----------+------------+------+\r\n|  1 | Ferrandez | S\u00e9bastien  |   10 |\r\n|  2 | Ferrandez | Christophe |   12 |\r\n|  3 | G\u00e9rard    | Olivier    |    9 |\r\n|  4 | G\u00e9rard    | olivier    |   15 |\r\n|  5 | Ferrandez | Christophe |   17 |\r\n|  6 | Ferrandez | S\u00e9bastien  |    8 |\r\n|  7 | G\u00e9rard    | Jean       |    4 |\r\n|  8 | Django    | Marina     |   17 |\r\n+----+-----------+------------+------+<\/pre>\n<h1>Le but<\/h1>\n<p>Je souhaite connaitre la ou les personne(s) qui ont obtenu la note la plus haute.<\/p>\n<h1>Les fa\u00e7ons de faire<\/h1>\n<h2>A l&rsquo;instinct&#8230;<\/h2>\n<p>Je sais qu&rsquo;il est question de <strong>MAX<\/strong> quelque part, je serais tent\u00e9 de faire :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSELECT max(note), nom, prenom FROM eleves;\r\n<\/pre>\n<p>Mais l\u00e0, deux probl\u00e8mes se posent&#8230;<\/p>\n<ul>\n<li>1 : je n&rsquo;ai qu&rsquo;un enregistrement alors que deux \u00e9l\u00e8ves ont la meilleure note<\/li>\n<li>2 : en face de cette meilleure note, je n&rsquo;ai pas le bon couple nom\/pr\u00e9nom<\/li>\n<\/ul>\n<h2>La jointure externe<\/h2>\n<p>Ici, nous allons nous baser sur la pr\u00e9sence d&rsquo;un marqueur <strong>NULL<\/strong> pour remonter les enregistrements qui nous int\u00e9ressent. Nous disons en substance \u00ab\u00a0Je veux le nom et le pr\u00e9nom des \u00e9l\u00e8ves pour lesquels il n&rsquo;existe pas de note qui soit plus grande\u00a0\u00bb.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSELECT s1.note, s1.nom, s1.prenom\r\nFROM eleves s1\r\nLEFT JOIN eleves s2 ON (s1.note &lt; s2.note)\r\nWHERE s2.id IS NULL\r\n<\/pre>\n<p>Cette solution l\u00e0 ram\u00e8ne bien les bons r\u00e9sultats :<\/p>\n<pre>\r\nmysql> SELECT s1.note, s1.nom, s1.prenom\r\n    -> FROM eleves s1\r\n    -> LEFT JOIN eleves s2 ON (s1.note < s2.note)\r\n    -> WHERE s2.id IS NULL;\r\n+------+-----------+------------+\r\n| note | nom       | prenom     |\r\n+------+-----------+------------+\r\n|   <strong>17 | Ferrandez | Christophe<\/strong> |\r\n|   <strong>17 | Django    | Marina <\/strong>    |\r\n+------+-----------+------------+\r\n2 rows in set (0.00 sec)\r\n<\/pre>\n<p>Le temps d&rsquo;ex\u00e9cution est de l&rsquo;ordre de la milliseconde (inf\u00e9rieur \u00e0 une dizaine de millisecondes), nous n&rsquo;avons pas index\u00e9 quelque champ que ce soit donc tout semble correct. Mais votre jeu de donn\u00e9es grossissant, vous allez vite vous rendre compte que cette solution n&rsquo;est pas viable ! Sur une table de 100000 enregistrements, une telle requ\u00eate (avec le champ note index\u00e9 !) prend plus de 17 minutes \u00e0 s&rsquo;ex\u00e9cuter&#8230;Nous serions bons pour le peloton d&rsquo;ex\u00e9cution avec un tel temps d&rsquo;ex\u00e9cution !<\/p>\n<h2>La sous-requ\u00eate<\/h2>\n<p>Il nous reste la solution de la sous-requ\u00eate, qui va s&rsquo;av\u00e9rer dans notre cas la plus performante :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSELECT  note, nom, prenom\r\nFROM   eleves\r\nWHERE  note=(SELECT MAX(note)\r\n              FROM eleves)<\/pre>\n<p>Sur notre set de 100000 enregistrements, avec le champ note index\u00e9, elle met 0.04 secondes \u00e0 s&rsquo;ex\u00e9cuter, nous sommes loin des 17 minutes de la jointure externe, qui semblait bien fonctionner sur un petit nombre d&rsquo;enregistrements. Un EXPLAIN nous montre que <\/p>\n<pre>\r\n+----+-------------+--------+------+---------------+------+---------+-------+------+------------------------------+\r\n| id | select_type | table  | type | possible_keys | key  | key_len | ref   | rows | Extra                        |\r\n+----+-------------+--------+------+---------------+------+---------+-------+------+------------------------------+\r\n|  1 | PRIMARY     | eleves | ref  | note          | note | 1       | const |    2 | Using where                  |\r\n|  2 | SUBQUERY    | NULL   | NULL | NULL          | NULL | NULL    | NULL  | NULL | Select tables optimized away |\r\n+----+-------------+--------+------+---------------+------+---------+-------+------+------------------------------+\r\n2 rows in set (0.00 sec)\r\n\r\n<\/pre>\n<p>\u00ab\u00a0<em>Select tables optimized away<\/em>\u00a0\u00bb signifie que notre sous-requ\u00eate ne contient qu&rsquo;une fonction agr\u00e9gative (sans groupement) et que l&rsquo;optimiseur MySQL a d\u00e9termin\u00e9 qu&rsquo;il ne renverra qu&rsquo;une seule et unique valeur.<\/p>\n<p>En conclusion, nous voyons que la sous-requ\u00eate est la plus adapt\u00e9e \u00e0 notre cas ici. Pourquoi ne pas tenter un petit <strong>GROUP_CONCAT<\/strong> ordonn\u00e9, \u00e9galement ? La requ\u00eate reste performante et les r\u00e9sultats sont pr\u00e9sent\u00e9s de mani\u00e8re \u00ab\u00a0agr\u00e9able\u00a0\u00bb&#8230;<\/p>\n<pre>\r\nmysql> SELECT note, GROUP_CONCAT( nom,  ' ', prenom\r\n    -> ORDER BY nom ) AS  \"Eleves\"\r\n    -> FROM eleves\r\n    -> WHERE note = ( \r\n    -> SELECT MAX( note ) \r\n    -> FROM eleves );\r\n+------+------------------------------------+\r\n| note | Eleves                             |\r\n+------+------------------------------------+\r\n|   17 | Django Marina,Ferrandez Christophe |\r\n+------+------------------------------------+\r\n<\/pre>\n<p>N&rsquo;\u00e9coutez pas les oiseaux de malheur qui vitup\u00e8rent constamment les sous-requ\u00eates, souvent ils n&rsquo;en n&rsquo;ont jamais fait une seule de leur vie et propagent des racontars qu&rsquo;ils lisent \u00e7a et l\u00e0 sur des forums g\u00e9n\u00e9ralistes o\u00f9 prolif\u00e8rent leurs cong\u00e9n\u00e8res aux avis biais\u00e9s ou erron\u00e9s&#8230;Dans certains cas, ces sous-requ\u00eates se r\u00e9v\u00e9leront bien plus efficaces que des jointures internes ou externes hasardeuses&#8230;Votre seule jauge quand vous \u00e9crivez une requ\u00eate c&rsquo;est <strong>EXPLAIN<\/strong> et pas le coll\u00e8gue ignare qui propage des l\u00e9gendes urbaines informatiques !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Si vous lisez r\u00e9guli\u00e8rement les billets de ce blog (ce que j&rsquo;esp\u00e8re secr\u00e8tement), vous savez que j&rsquo;essaie dans la mesure du possible de parler de choses qui servent au quotidien \u00e0 la fois pour les d\u00e9veloppeurs Web utilisant PHP mais aussi pour les personnes qui travaillent avec des bases de donn\u00e9es (relationnelles ou pas). C&rsquo;est [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[2],"tags":[56,58,57],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.6.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d&#039;un champ - La Fabrique de code - Tech blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d&#039;un champ - La Fabrique de code - Tech blog\" \/>\n<meta property=\"og:description\" content=\"Si vous lisez r\u00e9guli\u00e8rement les billets de ce blog (ce que j&rsquo;esp\u00e8re secr\u00e8tement), vous savez que j&rsquo;essaie dans la mesure du possible de parler de choses qui servent au quotidien \u00e0 la fois pour les d\u00e9veloppeurs Web utilisant PHP mais aussi pour les personnes qui travaillent avec des bases de donn\u00e9es (relationnelles ou pas). C&rsquo;est [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/\" \/>\n<meta property=\"og:site_name\" content=\"La Fabrique de code - Tech blog\" \/>\n<meta property=\"article:published_time\" content=\"2013-06-05T13:13:17+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/06\/happy-graduate.jpg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary\" \/>\n<meta name=\"twitter:creator\" content=\"@LaFabrique2Code\" \/>\n<meta name=\"twitter:site\" content=\"@LaFabrique2Code\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/\",\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/\",\"name\":\"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d'un champ - La Fabrique de code - Tech blog\",\"isPartOf\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#website\"},\"datePublished\":\"2013-06-05T13:13:17+00:00\",\"dateModified\":\"2013-06-05T13:13:17+00:00\",\"author\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162\"},\"breadcrumb\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"http:\/\/www.lafabriquedecode.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d&rsquo;un champ\"}]},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#website\",\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/\",\"name\":\"La Fabrique de code - Tech blog\",\"description\":\"PHP objet, MySQL, Design Patterns, OOP...et plus !\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/www.lafabriquedecode.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Person\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g\",\"caption\":\"admin\"},\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/author\/admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d'un champ - La Fabrique de code - Tech blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/","og_locale":"fr_FR","og_type":"article","og_title":"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d'un champ - La Fabrique de code - Tech blog","og_description":"Si vous lisez r\u00e9guli\u00e8rement les billets de ce blog (ce que j&rsquo;esp\u00e8re secr\u00e8tement), vous savez que j&rsquo;essaie dans la mesure du possible de parler de choses qui servent au quotidien \u00e0 la fois pour les d\u00e9veloppeurs Web utilisant PHP mais aussi pour les personnes qui travaillent avec des bases de donn\u00e9es (relationnelles ou pas). C&rsquo;est [&hellip;]","og_url":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/","og_site_name":"La Fabrique de code - Tech blog","article_published_time":"2013-06-05T13:13:17+00:00","og_image":[{"url":"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/06\/happy-graduate.jpg"}],"author":"admin","twitter_card":"summary","twitter_creator":"@LaFabrique2Code","twitter_site":"@LaFabrique2Code","twitter_misc":{"\u00c9crit par":"admin","Dur\u00e9e de lecture estim\u00e9e":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/","url":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/","name":"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d'un champ - La Fabrique de code - Tech blog","isPartOf":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/#website"},"datePublished":"2013-06-05T13:13:17+00:00","dateModified":"2013-06-05T13:13:17+00:00","author":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162"},"breadcrumb":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/"]}]},{"@type":"BreadcrumbList","@id":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/06\/mysql-max\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"http:\/\/www.lafabriquedecode.com\/blog\/"},{"@type":"ListItem","position":2,"name":"MySQL MAX : la\/les ligne(s) contenant la plus grande valeur d&rsquo;un champ"}]},{"@type":"WebSite","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#website","url":"http:\/\/www.lafabriquedecode.com\/blog\/","name":"La Fabrique de code - Tech blog","description":"PHP objet, MySQL, Design Patterns, OOP...et plus !","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/www.lafabriquedecode.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fr-FR"},{"@type":"Person","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162","name":"admin","image":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/image\/","url":"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g","contentUrl":"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g","caption":"admin"},"url":"http:\/\/www.lafabriquedecode.com\/blog\/author\/admin\/"}]}},"_links":{"self":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/549"}],"collection":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/comments?post=549"}],"version-history":[{"count":17,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/549\/revisions"}],"predecessor-version":[{"id":567,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/549\/revisions\/567"}],"wp:attachment":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/media?parent=549"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/categories?post=549"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/tags?post=549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}