MySQL - Indexes (combinés) - Avis

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous, je viens prendre vos avis SVP sur une bonne utilisation des indexes (combinés).

Ma première question SVP :

_Si dans une table j’ai une colonne qui a déjà un index unique, est-ce que c’est une mauvaise pratique d’aussi l’ajouter dans un autre index combiné avec une autre colonne ? (ce qui veut dire que cette colonne sera dans 2 indexes).

Mon autre question SVP :

Exemple simple :

J’ai 2 vues.

J’ai une vue pour afficher une X page spécifique :

select * from `pages` where `pages`.`status` = 1 and `slug` = 'page-25' limit 1

PS : status = 1 c’est pour récupérer uniquement les pages publiées.

J’ai une vue pour afficher le listing des pages :

select * from `pages` where `pages`.`status` = 1 limit 50

_ Vous me conseillez quoi comme indexes SVP ?

(Actuellement j’ai juste un index unique sur la colonne slug)

  • De uniquement garder mon index (index unique) sur la colonne slug ?

  • D’ajouter aussi un autre index sur la colonne status.

  • Ou d’ajouter un index combiné sur les colonnes status et slug ?

MErci d’avance

+0 -0

Bonsoir,

Pour ta première question:

Si tu fais souvent des requêtes sur les champs X et Y ensemble, alors oui, c’est certainement intéressant de créer un index pour le couple, mais en même temps ça dépend des requêtes exactes que tu fais. Pour t’assurer que l’index est bien utilisé, sers-toi de la commande explain / describe (après avoir créé l’index). La sortie t’indique si l’index est effectivement utilisé ou non pour cette requête.

Par contre, si tu as déjà un index sur X et Y, alors il est totalement inutile de créer un index sur X uniquement. Plus généralement, ça ne sert à rien de créer un index qui est le préfixe d’un autre. En effet, l’index sur X,Y peut aussi parfaitement être utilisé quand tu fais une requête sur X uniquement.

Attention par contre, des index sur Y seul ou sur Y,X peuvent avoir leur utilité pour d’autres requêtes, complètement indépendamment de l’index sur X,Y. Attention aussi au fait qu’un index sur X,Y ne pourra pas être utilisé pour une requête portant sur Y mais pas sur X.

Pour ta deuxième question:

Il faut garder à l’esprit que ton index sur slug ne sert absolument à rien dans la requête qui liste les pages, sauf si

  • Dans le select, tu ne demandes que des champs qui se trouvent dans ce seul et même index
  • Ou si l’index est trié et si tu tries les résultats dans le même ordre

Dans le premier cas, le moteur peut aller lire toutes les données dont il a besoin juste en lisant l’index. C’est très avantageux, tu remplaces un scan de la table par un scan de l’index qui est forcément plus petit et donc plus rapide.

Dans le deuxième cas, pour une requête paginée, tu permets au moteur de commencer la lecture de la table à un point précis plutôt qu’au début à chaque fois. En moyenne sur toutes les exécutions de cette requête, tu ne scan ainsi que la moitié de la table plutôt que la table entière. Ceci dit ça reste à vérifier, je ne suis même pas sûr que MySQL/MariaDB utilise effectivement cette possibilité.

Dans tous les autres cas, un scan complet de la table sera de toute manière nécessaire, l’index est totalement inutile.

Il ne faut pas oublier qu’un index sert à indiquer où aller chercher des données dans la table, pour ne pas avoir à la lire en entier. Donc si ta requête n’a pas de condition sur une donnée indexée, l’index ne sert à rien.

Petite aparetée: tu n’as pas de condition sur slug, mais tu as la condition status=1 dans ta requête par contre, donc on pourrait se demander si un index sur status serait utile.

Je suppose que la grande majorité de tes pages sont publiées. Du coup l’index qui t’indiquerait que tu dois aller presque tout lire ne servirait pas à grand chose. On appelle ça la sélectivité. Plus elle est petite, ou, dit autrement, plus la condition a le pouvoir d’éliminer des cas, plus l’index est intéressant. Note que c’est directement lié aux différentes valeurs possibles pour le champ et à leur fréquence d’apparition. Si on admet que status ne peut prendre que la valeur 1 (publié) ou 0 (non publié), au mieux la sélectivité ne pourra être que de 50%. C’est pas hyper sélectif, donc pas très intéressant.

Pour le cas de la requête simple qui récupère une page précise, la réflexion est en fait un peu dans le même genre. Inclure status dans l’index peut permettre de faire un court-circuit rapide, i.e. éviter d’aller lire les autres données dans la table si on voit directement dans l’index que rien ne correspond à ce qu’on cherche.

Ca ne me parait pas très utile, dans le sens où on s’attend à ce que, dans l’écrasante majorité des exécutions de la requête, la page demandée existe et est bien publiée. Ca pourrait éventuellement faire une différence significative si on s’attendait majoritairement plutôt à l’inverse, et encore, je n’y crois pas trop.

Là pour moi la balance entre l’avantage potentiel déjà très discutable que ça peut apporter, et l’ajout d’une donnée supplémentaire dans l’index est vite faite: d’après moi ça ne vaut clairement pas la peine.

+0 -0

Merci à tous pour vos réponses.

Par contre, si tu as déjà un index sur X et Y, alors il est totalement inutile de créer un index sur X uniquement.

Sauf si sur X j’ai aussi besoin de vérifier l’unicité. Avec mon langage de programmation, avant de valider un insert/update d’une page/article je check que le slug n’est pas déjà pris. Mais je pense que c’est aussi très important d’ajouter des indexes uniques en BDD.

Je me suis amusé avec PhpMyAdmin à faire quelques tests avec explain.

Est-ce vraiment utile de mettre un index sur une colonne qu’on utilise en ORDER BY (mais jamais en WHERE) ?

Dans Google je lit que oui. Mais ces tests (en mettant un index sur les colonnes "status" et "published_at") :

explain select `articles`.* from `articles` where `articles`.`status` = 1 order by `articles`.`published_at` desc;

Ici à possible_keys j’ai : articles_status_index

Pourtant je fais bien un ORDER BY sur "published_at".

Donc l’index sur "published_at" ne sert à rien ?

Si je fais la meme req SQL, mais cette fois pour mon test j’ajoute "published_at" dans mon WHERE :

explain select `articles`.* from `articles` where `articles`.`status` = 1 and `articles`.`published_at` is not null order by `articles`.`published_at` desc;

Ici à possible_keys j’ai : articles_status_index,articles_published_at_index

+0 -0

Si tu as un index sur X, et c’est un index unique, alors un index sur X,Y n’aura à peu près aucun intérêt. Le seul cas où il peut apporter quelque chose, c’est quand il va permettre d’éviter de lire dans la table (toutes les données sont dans cet index sur X,Y), mais ça ma paraît un très mauvais argument.

Si tu as souvent des requêtes avec un filtre sur status, mais aucune clause sur slug, alors il faut un index sur status. Mais j’imagine que la majorité de tes requêtes ont une clause sur slug, et donc ton index unique suffit. (Et créer d’autres indexes serait une cause de baisse de performance).

Si tu constates des problèmes de performance, parfois la question n’est pas 'ajouter ou retirer des index’, mais faire en sorte que les indexes fonctionnent bien. Et pour ça, regarde du côté de Analyze table

Dans le doute, tu peux créer les index et demander à MySQL de te dire quels index sont utilisés. Sur MySQL je ne sais pas, mais avec d’autres SGBD une analyze te donne ces informations.

C’est utile en particulier dans le cas d’index multiples et/ou multi-colonnes, parfois c’est assez compliqué de savoir à priori quel(s) index sont utilisés dans quels cas.

Est-ce vraiment utile de mettre un index sur une colonne qu’on utilise en ORDER BY (mais jamais en WHERE) ?

En général pas vraiment. Sauf si cet index t’évite complètement de lire dans la table, mais c’est pas un cas d’usage très courant en-dehors de petites tables de jointure.

La colonne possible keys t’indique uniquement des indexs potentiellement utilisables. Ceux qui sont réellement utilisés sont explicités dans une autre colonne. Si rien n’est précisé, c’est qu’au final l’index n’est pas utilisé.

Comme je l’ai déjà dit dans mon précédent message et comme elegance le confirme de manière beaucoup plus directe, un index double (slug, status) ne sert à rien si tu as déjà un index sur slug. En général il n’est pas très utile de rajouter des autres colonnes derrière un index avec unicité. C’est peut-être même contre-productif.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte