Optimisation
Il faut toujours essayer de structurer vos donnĂ©es et vos requĂȘtes pour une performance optimale, en utilisant les techniques dĂ©jĂ vues dans ce cours :
Formes normalisées, contraintes etc
RequĂȘtes :
Pas de
select *
(récupérez uniquement les attributs nécessaires)Utilisation de la clause
where
pour bien filtrer les données avant la transmissionUtilisation de la pagination
Mais, quand une table devient trĂšs grande, on commence Ă constater des problĂšmes de performance.
On fait une requĂȘte sur un attribut qui nâest pas une clĂ© ?
On demande trop de jointures ou de sous-requĂȘtes ?
Comment réagir en temps réel ?
Avant d'optimiser, mesurer !
Identifier et mesurer
Vous constatez une lenteur dans votre application web ou smartphone. Il faut réagir avant de perdre des clients !
La premiĂšre Ă©tape est de lancer une enquĂȘte de la source de la lenteur. En revanche, ce n'est pas si simple parce que la source peut-ĂȘtre Ă plusieurs endroits de votre stack :
Votre logique et/ou code et pas optimale (exemple, dans PHP le templating prend trop de temps ?)
La transmission de données prend trop de temps ?
Vous transmettez trop de données, ou des données inutiles ?
Votre architecture a suffisamment de bande-passante pour la demande ?
Le SGBDR répond trop lentement ?
Les requĂȘtes SQL produisent trop de produits cartĂ©siens ?
La SGBDR répond vite, mais cette opération est trÚs souvent sollicitée
Les ressources disponibles au SGBDR ne sont pas suffisants ?
Comme vous voyez, il y a plusieurs sources potentielles du problĂšme.
Souvent, la solution la plus rapide, mais la plus chÚre, est-ce qu'on appelle vertical scaling. C'est-à -dire, on paye pour les ressources supplémentaires :
payer une meilleure bande passante
payer une infrastructure plus puissante pour le SGBDR
En revanche, cette solution n'est pas seulement chĂšre, elle ne traite que les symptĂŽmes du problĂšme.
Pour trouver la cause du problĂšme de performance, il faut maĂźtriser tous les outils Ă notre disposition afin de trouver la cause exacte :
Dans votre API, est-ce qu'il y a des outils d'observation ?
console.time
etconsole.timeEnd()
dans JavaScript sont des outils simples mais efficaces pour observer oĂč se trouve des bouchons dans votre code.Est-ce que vous avez des journaux que vous pouvez analyser, pour crĂ©er des synthĂšses, et identifier les requĂȘtes les plus lentes ou les plus frĂ©quemment appelĂ©s ?
Est-ce que les différentes briques de votre architecture (comme votre SGBDR) disposent des modules d'observation ?
Le processus d'optimisation
Constatez : on commence par constater des ralentissements Ă certains endroits
Mesurer : on utilise (ou met en place) des outils d'observation afin de noter exactement oĂč se trouve de ralentissements
Identifier : suite aux mesures, on identifie des requĂȘtes, modules, bloques de code, sous-systĂšmes qui prennent le plus de temps
Répéter 2 et 3 : on répÚte de façon drill down, en rentrant dans le détail dans le but de trouver le module le plus bas niveau responsable du problÚme
Tests automatiques : est-ce qu'on a des tests automatiques que valide le comportement des modules concernés par le problÚme ? Sinon, avant l'intervention, rédiger les !
Intervention : on effectue l'opĂ©ration d'optimisation. Une reformulation d'une requĂȘte SQL, la mise en place d'une cache, remanier du code, etc.
Mesurer : est-que notre intervention a amélioré la performance ? Sinon, l'intervention ne sert à rien !
Tester : tourner vos tests automatiques. Votre intervention n'a rien cassé ?
Outils d'observation
MariaDB, comme tous les SGBDR, dispose des outils d'observation qui nous aident dans nos efforts d'observation.
Nous utiliserons une base de données réelle afin de tester nous outils d'observation et optimisation :
Téléchargez et importer cette base dans votre SGBDR local.
Journaux
Il y a deux sortes de journal possible dans MariaDB :
slow query log
: enregistre des requĂȘtes qui prennent trop de temps Ă exĂ©cutergeneral log
: enregistre toutes les requĂȘtes
Pour savoir si ces journaux sont activés ou pas :
Et :
On voit que par défaut ses journaux sont désactivés (pour optimiser la performance et l'utilisation de la place disque).
On peut les activer en modifiant le fichier de configuration de MariaDB :
Exercice Créez le fichier mariadb.cnf
et l'inclure dans votre Container local en suivant les instructions sur cette page. Validez avec les commandes dessus que les journaux soient bien activés.
Nous allons faire quelques requĂȘtes sur notre base de donnĂ©s nutrition
:
Vous constatez des problĂšmes de performance ?
Regardons les journaux !
2023-04-18 07:32:27.810283
root[root] @ localhost []
3
1
Query
select * from mysql.general_log order by event_time desc limit 5
2023-04-18 07:31:11.464773
root[root] @ localhost []
3
1
Query
select count(type) from Repas where type = 'petit_dejeuner'
2023-04-18 07:30:06.848528
root[root] @ localhost []
3
1
Query
select email, nom, prenom from User where departement like '%haut%'
Ici, on voit les requĂȘtes triĂ©es par la date d'Ă©vĂ©nement. Mais, on n'a pas de notion de la durĂ©e de chaque requĂȘte.
Regardons l'autre journal :
2023-04-18 07:31:31.304461
root[root] @ localhost []
00:00:19.839693
00:00:00.003751
1
838915
nutrition
0
0
1
select count(type) from Repas where type = 'petit_dejeuner'
3
0
Ici, on constate toutes les requĂȘtes qui ont pris plus qu'une seconde (le seuil Ă©tant dĂ©fini dans la variable long_query_time
dans mariadb.cnf
).
On a donc mesuré et identifié la source de notre problÚme.
Explain
Le mot clé explain
devant une requĂȘte va plutĂŽt dĂ©montrer le plan d'action formulĂ© par le SGBDR au lieu d'exĂ©cuter la requĂȘte. Il peut ĂȘtre utile pour optimiser nos requĂȘtes :
Valider que la clé primaire est utilisé, ou bien un attribut indexé est utilisé
Valider qu'il n'y a pas trop d'Ă©tapes inutiles dans le plan d'action
...
Pour plus d'information sur l'outil explain
, je vous dirige vers la page de documentation : https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
Vous vous souvenez de notre requĂȘte lente dans la base saas
?
Regardons le plan d'action :
1
SIMPLE
A
ALL
address_french_regionId
NULL
NULL
NULL
31521
Using where; Using temporary
1
SIMPLE
S
ALL
address_french_regionId
NULL
NULL
NULL
31521
Using where; Using join buffer (flat, BNL join)
Nous avons pu optimiser la requĂȘte en utilisant des sous-requĂȘtes :
1
PRIMARY
action
ALL
address_french_regionId
NULL
NULL
NULL
31521
Using where
2
SUBQUERY
action
ALL
address_french_regionId
NULL
NULL
NULL
31521
Using where
Il y a deux différences majeures :
On voit que dans les deux cas, on n'agit pas sur des clés primaires ni des attributs indexés : le champ
possible_keys
ne contient pas le motPRIMARY
ni defk...
.En revanche, on voit dans la colonne
extra
que la premiĂšre requĂȘte utilise des tampons mĂ©moire pour satisfaire la requĂȘte, ainsi qu'unjoin buffer
(pour le produit cartĂ©sien)On voit que la deuxiĂšme requĂȘte se compose en deux types :
PRIMARY
puisSUBQUERY
qui nous donne un indice que si la sous-requĂȘte s'exĂ©cute en premier, elle va rĂ©duire le champ de possibilitĂ©s pour la requĂȘtePRIMARY
Regardons pour la requĂȘte qu'on vient de faire sur la base nutrition
:
1
SIMPLE
Repas
ALL
NULL
NULL
NULL
NULL
818892
Using where
On voit qu'il n'y a aucune clĂ© primaire, Ă©trangĂšre ni indexe utilisĂ© pour la requĂȘte, et qu'on a 818k lignes Ă traiter ! Il y a de la place pour optimiser !
Dans cette requĂȘte, on filtre par l'attribut type
, qui en soit, n'est pas une clĂ© primaire. Si on peut organiser nos donnĂ©es pour plus facilement extraire des repas d'un certain type, on pourrait Ă©ventuellement optimiser notre requĂȘte.
Pour cela, on utilise des index.
Indexes
Ajouter un index est une façon dâoptimiser nos requĂȘtes. On sait dĂ©jĂ ce qu'une recherche par dichotomie est plus optimisĂ©e :
Alors pourquoi pas en profiter dans notre SGBDR !
En créant un index, on dit au SGBDR d'en effet créer une arborescence de données comme dans l'image pour plus rapidement trouver des données.
Créons un index pour l'attribut type
:
Vous allez remarquer que la création prend un peu de temps : c'est la construction de l'arborescence.
à tout moment, on peut afficher tous les index déjà en place :
Vous allez noter le mot BTREE
dans les résultats. Cela veut dire binary tree qui est le nom anglais de la structure utilisé pour la recherche par dichotomie.
Ou bien supprimer un index :
Clés primaires, valeurs uniques, contraintes par clé étrangÚre
On sait comment toutes ses fonctionnalités sont implémentées dans notre SGBDR ? Grùce aux index ! Quand on crée une clé primaire, ou désigne un attribut comme unique
, le SGBDR crée automatiquement un index pour l'attribut en question.
Par la suite, il serait plus facile et rapide pour le SGBDR de savoir si on crée des doublons !
Analysons le plan d'action pour notre requĂȘte lente maintenant :
1
SIMPLE
Repas
ref
ind_repas_type
ind_repas_type
1023
const
409446
Using where; Using index
On voit maintenant qu'on utilise bien l'indexe !
Testons ! Est-ce qu'on a rĂ©ussi Ă optimiser la requĂȘte ?
Index pour les recherches spéciales
On utilise aussi des index quand une requĂȘte agit sur un type de donnĂ©e non-standard. Ă la place de la dichotomie, les donnĂ©es seront organisĂ©es d'une façon d'optimiser la requĂȘte dans le domaine particulier de l'attribut.
Par exemple, pour les coordonnées géométriques, par exemple GPS, on va utiliser une représentation 2D de nos points de données, et ensuite, on va utiliser une structure comme un BSPTree
(binary space partition tree) pour plus rapidement chercher des points proches ou dans un rayon précis.
Dans MariaDB, il y a des index non-standards :
FULLTEXT
Effectuer des requĂȘtes de type
match
qui fonctionnent plus comme un moteur de recherche.
SPATIAL
Effectuer des requĂȘtes gĂ©o-spatial avec les coordonnĂ©es GPS (par exemple).
DerniĂšre mise Ă jour