Hello,
Un post pour vous démontrer que c’est toujours intéressant de lire les documentations et que parfois, les petites lignes en bas de page peuvent révéler des informations importantes.
J’étais récemment chez un client pour un audit de performance dans un environnement Windev / MySQL.
Je ne suis pas un grand spécialiste de Windev, bien qu’ayant déjà réalisé des audits sur ce type d’environnement, je n’avais jamais eu l’occasion d’aller aussi loin dans la compréhension du code applicatif.
Au hasard de l’analyse des requêtes lentes (via le log des requêtes lentes), je me suis aperçu qu’une requête apparaissait systématiquement deux fois consécutivement dans le log.
Après avoir identifié avec mon client le bout de code exécutant cette requête, nous avons travaillé avec le log général de MySQL afin d’essayer de comprendre pourquoi cette requête était lancée deux fois alors qu’elle n’apparaissait qu’une fois dans le code applicatif.
Le code utilisé est le suivant :
SD est une Source de Données
MaReq est une chaîne
####################################################################################
MaReq = "SELECT nom, prenom FROM client WHERE type = 1"
// Exécution de la requête
HExécuteRequêteSQL(SD, MaConnexionMySQL, hRequêteSansCorrection, MaReq)
// Boucle sur le résultat
HLitPremier(SD)
TANTQUE PAS HEnDehors(SD)
Trace(SD.Nom)
HLitSuivant(SD)
FIN
####################################################################################
Le verdict du log général est sans appel, la requête est bien exécutée deux fois !
Petite parenthèse, la fonction HExécuteRequêteSQL réalise systématiquement une modification de code SQL (Ajout d’un ORDER BY par exemple). Si vous souhaitez conserver votre code SQL original, n’oubliez pas d’ajouter le paramètre hRequêteSansCorrection comme fait ici.
Mais revenons à nos moutons, la mystérieuse requête en double…
Après plusieurs tests, nous avons réussi à identifier la cause de cette double exécution, il s’agissait de la fonction HLitPremier.
En effet, cette fonction exécute une nouvelle fois la requête, certainement pour intégrer d’éventuelles modifications de données entre le moment où l’on exécute la requête et le moment où l’on entre dans la boucle.
Simplement, si la requête est déjà coûteuse, elle l’est d’autant plus si elle est lancée deux fois et la seconde exécution n’est pas forcement nécessaire.
Cela dépend évidemment du contexte applicatif dans lequel vous vous trouvez. Dans le cas présent, ce n’était pas nécessaire.
Nous voici donc en train d’éplucher la documentation Windev (c’est là que vous comprenez mon introduction) à la recherche d’une information capitale dans notre cas : Comment désactiver cette double exécution ?
Et nous n’avons pas mis longtemps (enfin, un peu quand même…) à repérer de petites lignes en bas de la page de la documentation de l’accès natif MySQL pour Windev :
Optimisations des fonctions HyperFileSQL (Réf : http://doc.pcsoft.fr/fr-FR/?acces-natif-mysql-pour-windev-webdev)
- Les Tables fichiers basées sur des requêtes sont optimisées : il est possible de trier la table en cliquant sur une de ses colonnes.
- Pour éviter de ré-exécuter plusieurs fois la même requête lors du parcours de son résultat, il est conseillé d’utiliser la constante hSansRafraichir (par exemple si un seul poste modifie les données).
Donc, pour résumer, si vous utilisez la fonction HLitPremier et que vous ne souhaitez pas que celle-ci ré-exécute la requête précédemment exécutée par la fonction HExécuteRequêteSQL, vous devez utiliser la fonction avec le paramètre suivant :
- HLitPremier(SD, hSansRafraîchir)
Et effectivement, le log général ne mentionnait plus qu’une seule exécution après cette correction de code Windev !
J’espère que cette information vous sera utile pour vos devs Windev existants ou à venir. N’hésitez pas à nous faire un retour si vous aviez déjà rencontré ce problème ou pour tout retour d’expérience Windev / MySQL.
Un grand merci à toute l’équipe qui se reconnaitra et à bientôt sur le blog de capdata.
Cédric
Documentation sur le log des requêtes lentes : http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html
Documentation sur le log général : http://dev.mysql.com/doc/refman/5.1/en/query-log.html
Documentation Windev : http://doc.pcsoft.fr/fr-FR/
Continuez votre lecture sur le blog :
- Que faire des “[Warning] Aborted connection” avec MySQL ? (Benjamin VESAN) [MySQL]
- MySQL et les tables temporaires internes (Benjamin VESAN) [MySQL]
- La fin de mysql_upgrade à partir de MySQL 8.0.16 (Capdata team) [MySQL]
- Les dessous de la désactivation de ~/.mysql_history (David Baffaleuf) [MySQL]
- Nouveautés MySQL 8.0 : Configuration automatique de variables avec innodb_dedicated_server (Capdata team) [MySQL]