Bonjour,
Je viens de migrer une base mysql 5 vers mysql8 et depuis cette migration j'ai un facteur 10 dans le temps de réponse de certaines requêtes.
par ex soit la table suivante :
CREATE TABLE `val_hor` (
`date_time` datetime NOT NULL,
`id_station` varchar(10) NOT NULL,
`polluant` varchar(10) NOT NULL,
`value` double DEFAULT NULL,
PRIMARY KEY (`date_time`,`id_station`,`polluant`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Cette table contient plus de 19 millions de lignes
la requête suivante
SELECT COUNT(*) AS ct_date FROM `val_hor`
WHERE `id_station` = '14031'
AND date_time LIKE '2020-06-09%'
AND `polluant` = 'T' AND `value`!='-999';
prenait environs 4 secondes sur l'ancien serveur et maintenant plus de 40. En décomposant la requête, il semble que ce soit la partie date_time LIKE '2020-06-09%' qui entraine le ralentissement.
j'ai essayé de remplacer le like par un between mais c'est tjs aussi long.
Il y a 2 fois plus de RAM sur le nouveau serveur que sur l'ancien
le fichier my.cnf de l'ancienne base contenait les options suivantes que j'ai reporté sur la nouvelle
join_buffer_size = 512M
sort_buffer_size = 2M
read_rnd_buffer_size = 50M
Je suis preneur de toutes pistes permettant de résoudre cela
# Peut-être une piste
Posté par _kaos_ . Évalué à 4.
Salut,
Voir ici. L'algo à changé. Extrait :
Je ne sais pas si ça peut jouer, mais si ça peut être une piste…
Matricule 23415
[^] # Re: Peut-être une piste
Posté par _kaos_ . Évalué à 3. Dernière modification le 16 juin 2020 à 10:41.
Re salut,
Désolé, je crois que j'ai foiré sur le lien (j'étais probablement en train de lire la suite).
Donc, peut-être ici.
Matricule 23415
# et pourquoi pas
Posté par Anonyme . Évalué à 2.
doubler les valeurs de memoires dans my.conf ?
join_buffer_size = 1024M
sort_buffer_size = 4M
read_rnd_buffer_size = 100M
note : je ne suis pas spécialiste en sgbd, c'est juste une idée
# pas d'index?
Posté par wismerhill . Évalué à 4.
https://use-the-index-luke.com/
S'il n'y a pas d'index, ce sera forcément lent.
Ensuite, il ne faut pas utiliser des expressions rationnelles pour comparer des dates, même s'il y avait un index sur la colonne date_time, il ne serait pas utilisé parce que tu lui demande de convertir le timestamp en chaine de caractère.
Il y a des fonctions pour extraire une partie d'une date, ou convertir un timestamp en date.
Mais pour profiter d'un éventuel index, le mieux est d'utiliser l'opérateur between (ou équivalent).
[^] # Re: pas d'index?
Posté par Le Pnume . Évalué à 2.
merci pour vos réponses.
En l'occurrence, je dois gérer l'existant.j'ai fait des tests en ajoutant un index et je n'ai pas amélioré les performances.
La table d'origine sous mysql 5, n'avait pas plus d'index mais la requete allait 10 fois plus vite, je ne suis pas sur d'avoir fait de tests avec index et between, je m'y colle demain.
[^] # Re: pas d'index?
Posté par Le Pnume . Évalué à 2.
Pas d'avancée, j'ai ajouté un index simple sur le champs date_time, et fait mon select grâce à un CAST
Le temps de réponse de la requête est tjs de l'ordre de 40s
[^] # Re: pas d'index?
Posté par claudex . Évalué à 6.
Que donne un
EXPLAIN
sur ta requête ? (et si tu as encore l'ancien serveur pour comparer, c'est encore mieux).« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: pas d'index?
Posté par Le Pnume . Évalué à 2.
Bonne idée, je n'y avais pas pensé. Comme indiqué plus bas, j'ai trouvé un contournement mais je ferais un test avec explain sur les 2 serveurs dés que j'aurais un peu de temps.
[^] # Re: pas d'index?
Posté par wismerhill . Évalué à 2.
Forcément, si tu transforme la valeur de la colonne, l'index ne sera pas utilisé, c'est pour ça que j'indiquais d'utiliser between.
# Contournement
Posté par Le Pnume . Évalué à 4.
Merci à tous ceux qui m'ont répondu.
j'ai trouvé une version de la requête qui semble donner satisfaction :
avec cette requête la réponse est quasi immédiate.
ça n'explique pas les raisons de la perte de performance mais au moins ça permet d'avancer
[^] # Re: Contournement
Posté par _kaos_ . Évalué à 2.
Salut,
Comme je suis pas DBA, je ne peux pas expliquer pourquoi du coup ça marche mieux, mais merci d'avoir partagé une solution de contournement.
J'aime bien quand un contournement est trouvé, ça permet de se poser et réfléchir tranquillement ensuite pour du plus pérenne :)
Matricule 23415
[^] # Re: Contournement
Posté par wismerhill . Évalué à 4.
Oui, parce que là l'index sur date_time peut être utilisé, c'est à peu près équivalent au between (je ne sais plus s'il correspond à des <= >= ou à des < >) que je recommandais plus haut.
Tu devrais le voir dans un explain.
Ce n'est pas étonnant que le query plan soit très différent quand on fait un changement de version majeure, surtout sur une requête qui n'était pas du tout optimisée (4s, c'était déjà horriblement lent pour une requête qui ne devrait ressortir que peu de résultats).
# Curiosité
Posté par DontShootMe . Évalué à 1.
Je ne suis pas expert en la matière, mais te serait-il possible de faire un test avec cette requête :
Le but ici est de "caster" les deux parties de l'égalité en date et laisser MySQL comparer deux choses de même type :
# Normalisation
Posté par champomy62 . Évalué à 2.
Je connais pas MySQL mais disons:
Si tu as un type datetime, utilise les operateurs liés aux dates. La requête que tu montrais traité surement le prédicat comme une chaine de caractère!
Ensuite tu as bien un index sur ta clé primaire automatiquement mais pas sur value. Cela pourrait etre interessant d'en rajouter un et voir meme de faire une corrélation entre les valeurs ?
D'ailleurs, je trouve la clé primaire un peu mal définie. en fait, a en déduire la définition de la table, tu te retrouveras avec beaucoup de duplications.
Tu pourrais surement créer une table polluant et stations et faire des belles jointures :)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.