Cette page décrit Calíope 1.8, la version que je construis en ce moment. La 1.7 est sur l'App Store pour Mac, iPad, iPhone, Apple Watch, Apple TV et Apple Vision Pro. Le changelog indique dans quelle version chaque fonction est arrivée.

Ajoute un bouton « Ouvrir dans Calíope » à chaque sujet. Ne fonctionne qu'avec l'app installée.

Requêtes lentes du serveur

Le journal des requêtes lentes

Ce que le serveur a noté de lui-même sur les requêtes ayant dépassé son seuil, pour tous ses clients.

Où le trouver : Espace de travail › Outils › Requêtes lentes

Voici ce que le serveur a noté de lui-même : les requêtes qui ont dépassé son seuil, venant de tous ses clients et pas seulement de Calíope. Le journal des requêtes de l'app est autre chose —ce que vous avez exécuté d'ici— et il a son propre outil.

La barre propose jusqu'à trois vues, et lesquelles existent dépend du serveur : Réglages, toujours ; Entrées, une ligne par exécution, seulement si le moteur conserve les exécutions individuelles et laisse un client les lire ; Par instruction, le résumé groupé par forme de requête, seulement si le moteur le publie. Une vue que le serveur ne peut pas remplir n'est pas dessinée en grisé : elle n'est pas dessinée.

MySQLMariaDBAurora

La famille MySQL donne les deux : mysql.slow_log conserve les exécutions —avec leur heure, leur utilisateur et le texte littéral— et performance_schema conserve le résumé par forme.

TiDB

TiDB donne les deux, depuis d’autres tables : les exécutions viennent de CLUSTER_SLOW_QUERY, qui lit le fichier tidb-slow.log de chaque nœud —sans les requêtes que TiDB lance de lui-même—, et le résumé par forme, de STATEMENTS_SUMMARY.

PostgreSQL

PostgreSQL écrit les exécutions dans son fichier journal, et Calíope le lit en SQL (pg_ls_logdir() et pg_read_binary_file()) quand le serveur a le collecteur allumé (logging_collector = on), un format d’une ligne par exécution (jsonlog ou csvlog dans log_destination) et que votre compte peut le lire (pg_monitor et pg_read_server_files) ; s’il manque quelque chose, Entrées dit quoi. L’agrégat vient de pg_stat_statements, dans Par instruction.

SQL Server

SQL Server n’a pas de journal des requêtes lentes à lui, alors Calíope en crée un : une session Extended Events, caliope_slow_statements, qui enregistre chaque instruction au-delà du seuil. Ce sont les Entrées, et la session s’active depuis Réglages. Par instruction est autre chose : le décompte que le serveur tient toujours de chaque plan en cache.

Pour voir une ligne entière —le texte complet et tout ce que le serveur a noté— double-cliquez dessus sur le Mac ou touchez-la sur l'iPad. Depuis sa fiche, la requête se copie ou part vers l'éditeur.

Le sélecteur de droite dit combien de lignes sont demandées : cinquante pour voir ce qui se passe maintenant, mille pour examiner la journée entière. L'actualisation automatique relit toutes les dix secondes, et la barre indique à quelle heure ce que vous voyez a été lu.

Oracle

Oracle n'a pas de journal des requêtes lentes : ni seuil du serveur ni exécutions enregistrées une à une. Ce qui est lu, c'est le cache d'instructions (V$SQL), qui tient toujours les chiffres de chaque instruction tant qu'elle y reste. Entrées montre une ligne par instruction à son exécution moyenne —temps, CPU, lectures et lignes divisés par le nombre d'exécutions, affiché à côté— et Par instruction, le résumé groupé par forme. Ce n'est pas un historique : une instruction qui sort du cache disparaît avec ses chiffres, et un redémarrage le vide. Les requêtes internes de SYS et SYSTEM n'apparaissent pas, sauf les vôtres si vous vous connectez avec l'un de ces comptes. Lire V$SQL demande un privilège de dictionnaire (SELECT_CATALOG_ROLE ou SELECT ANY DICTIONARY) ; sans lui, l'écran montre l'erreur du serveur. AWR et les vues DBA_HIST_* ne sont pas consultés : ils exigent un pack payant d'Oracle. Masquer celles de Calíope cache ce que Calíope interroge de son côté —ses instructions commencent par la marque /*Caliope*/—, jamais ce que vous avez écrit dans l’éditeur.

ClickHouse

ClickHouse donne les deux depuis system.query_log : les exécutions, lues juste après un SYSTEM FLUSH LOGS pour que ce qui vient de s'exécuter y soit déjà, et le résumé par forme. Les exécutions incluent celles qui ont échoué, avec leur erreur dans une colonne à part, et donnent les octets lus et la mémoire après le temps ; l'heure est celle de l'horloge du serveur. Masquer celles de Calíope, activé par défaut, masque ce que Calíope interroge de lui-même, jamais ce que vous avez écrit dans l'éditeur.

Apple Vision Pro : comme sur iPad : regardez la ligne et pincez pour l'ouvrir.

Mots-clés : requêtes lentes, slow query log, performance, serveur, seuil, journal

Réglages, moteur par moteur

Activer le journal, déplacer le seuil et choisir où il écrit — là où le serveur permet de le faire d'ici.

Où le trouver : Requêtes lentes › Réglages

Les cartes du haut disent ce que le serveur répond à cet instant : s'il enregistre, avec quel seuil et où il écrit. En dessous apparaît l'une de deux choses : les contrôles pour le changer, ou une note qui dit où cela se change vraiment. Jamais des contrôles grisés, qui ne distinguent pas « pas ici » de « c'est cassé ».

Le seuil se tape ou se déplace avec les boutons moins et plus, et s'envoie avec Appliquer. Un seuil négatif est refusé ici même : aucune requête ne dure moins que rien, et le serveur ne le refuserait pas : selon le moteur, il le ramène à zéro —toute requête deviendrait alors lente et le journal grossirait sans frein— ou le change en une autre valeur sans rien dire.

MySQLMariaDBAurora

Le seuil est en secondes (long_query_time), et la destination se choisit entre la table mysql.slow_log, le fichier du serveur, ou les deux (log_output). Seul ce qui va dans la table est lisible depuis un client.

Deux choses qui surprennent : un changement fait d'ici ne survit pas à un redémarrage du serveur —pour cela il va dans son fichier de configuration— et n'atteint pas les connexions déjà ouvertes, celle de Calíope comprise : les sessions vivantes continuent de mesurer avec l'ancienne valeur jusqu'à leur recyclage.

Aurora

Sur Amazon Aurora ces réglages ne vivent pas dans le serveur mais dans le groupe de paramètres du cluster, donc vous verrez ici la note au lieu des contrôles. Vider le journal reste possible : le serveur le fait lui-même avec mysql.rds_rotate_slow_log.

TiDB

Le seuil est tidb_slow_log_threshold, et le serveur le tient en millisecondes : ici, il se saisit en secondes, comme pour les autres moteurs, et la liste de la fin montre la valeur du serveur avec son unité. long_query_time existe et ne gouverne rien. Un seuil négatif, dans TiDB, fait le tour et devient un seuil si haut que rien n’est enregistré.

La destination ne se choisit pas : TiDB écrit toujours dans le fichier de chaque nœud et le publie comme une table. Un changement fait d’ici atteint aussitôt toutes les connexions de ce nœud, dont celle de Calíope, et dure jusqu’au redémarrage du nœud : il revient alors à la valeur de sa configuration.

PostgreSQL

Le seuil est en millisecondes (log_min_duration_statement), et un changement fait d'ici persiste : il s'écrit avec ALTER SYSTEM et le serveur recharge sa configuration.

Mais certaines origines l'emportent sans le dire. Si la valeur vient de la ligne de commande avec laquelle le serveur a démarré, ou d'un réglage propre à cette base, à ce rôle ou à cette session, l'écriture est acceptée, le fichier reçoit la nouvelle valeur et celle qui s'applique reste l'ancienne. C'est pourquoi la première variable de la liste du bas est l'origine du seuil : c'est elle qui dit où il faut le changer. Quand l'origine est de celles-là, vous verrez ici la note et non les contrôles.

La destination ne se choisit pas d’ici : PostgreSQL écrit toujours dans son propre journal, un fichier de la machine du serveur, et Entrées le lit en SQL si le collecteur et le format sont en place.

SQL Server

Dans SQL Server, l’interrupteur crée et démarre la session Extended Events caliope_slow_statements, ou l’arrête. Elle vaut pour tout le serveur : elle enregistre les instructions de toutes les connexions, et avec STARTUP_STATE = ON elle redémarre avec lui. Le seuil est son prédicat (duration, en microsecondes côté serveur), et Écrit dans choisit entre La mémoire du serveur, jusqu’à son redémarrage (un ring_buffer, qui en garde environ mille) et Un fichier du serveur (un event_file dans son répertoire de données). La modifier demande l’autorisation ALTER ANY EVENT SESSION, et sans elle le refus la nomme ; la lire, VIEW SERVER STATE. Masquer celles de Calíope cache ce que Calíope interroge de lui-même, qui porte la marque /*Caliope*/ ; ce que vous tapez dans l’éditeur reste toujours visible. Le résumé Par instruction vient toujours du cache de plans : il se perd au redémarrage du serveur, et avec optimize for ad hoc workloads activé, une requête isolée n’y entre qu’à sa deuxième exécution.

La liste de la fin regroupe les variables que ce serveur publie autour du journal, avec les noms qu'il leur donne. Elles sont informatives : elles changent là où leurs réglages se changent, pas ici.

Oracle

Dans Oracle, le seuil appartient à Calíope, pas au serveur : il s'applique à la lecture, à l'exécution moyenne de chaque instruction, et il est enregistré dans ce profil. Le changer ne touche rien sur le serveur et vaut dès la lecture suivante. Il est en secondes, bien que le cache compte le temps en microsecondes ; si vous ne l'avez pas changé, c'est une seconde. Il n'y a pas d'interrupteur —le cache ne s'éteint pas— ni de destination à choisir : ce qui est lu vit dans la mémoire du serveur.

ClickHouse

Le serveur garde le seuil en millisecondes (log_queries_min_query_duration_ms), bien qu'ici il s'affiche en secondes, et la destination est toujours system.query_log. L'activation et le seuil s'enregistrent sur votre propre compte, avec ALTER USER … MODIFY SETTINGS, et valent pour les requêtes de ce compte à partir de la suivante, pas pour celles des autres. Si le compte est défini dans la configuration du serveur ou n'a pas ALTER USER, vous verrez la note au lieu des commandes. Vider le journal, c'est TRUNCATE TABLE system.query_log, pour tout le serveur. En dessous, Variables qui affinent le journal liste six paramètres de ce qui est gardé de chaque requête —à partir de quelle étape (log_queries_min_type), quelle fraction (log_queries_probability), où le texte est coupé et si les paramètres, les threads et les vues qu'elle a touchés sont gardés—, avec la valeur de votre compte ; là où le compte peut garder ses paramètres, chacun a un champ et Appliquer, et s'écrit comme le seuil.

Mots-clés : seuil, long_query_time, log_min_duration_statement, log_output, ALTER SYSTEM, parameter group

Le résumé par instruction

Il groupe par forme de requête, pas par exécution : il dit ce qui coûte sa journée au serveur.

Où le trouver : Requêtes lentes › Par instruction

Par instruction ne liste pas des exécutions : il groupe par la forme de la requête. Les littéraux sont remplacés par un marqueur, donc mille requêtes qui ne diffèrent que par la valeur cherchée font une ligne, avec ses appels, son temps total et son temps moyen. C'est la réponse à « qu'est-ce qui coûte sa journée à ce serveur ? », qui n'est presque jamais la requête la plus lente.

MySQLMariaDBAurora

C'est performance_schema qui le publie, et les littéraux sortent en ?. Sur MariaDB il naît désactivé : si cette vue dit qu'il n'y a pas de résumé, ce n'est pas qu'il n'y a pas de requêtes lentes — c'est que performance_schema est à OFF. Il ne s'active pas serveur en marche : cela va dans son fichier de configuration et il faut le redémarrer.

TiDB

C’est STATEMENTS_SUMMARY qui le publie, et les littéraux sortent en ?. Il n’accumule pas depuis le démarrage : c’est la fenêtre en cours, que le serveur ferme et rouvre toutes les tidb_stmt_summary_refresh_interval secondes (1800 par défaut), donc les appels comptent depuis le début de cette fenêtre. Si le résumé est désactivé (tidb_enable_stmt_summary), il s’active sans redémarrage, avec SET GLOBAL. Réinitialiser les statistiques n’apparaît pas : aucune instruction ne le vide.

PostgreSQL

C'est pg_stat_statements qui le publie, et les littéraux sortent en $1. Il faut deux choses, toutes deux hors de l'app : la bibliothèque préchargée dans shared_preload_libraries, ce qui exige de redémarrer le serveur, et l'extension créée dans cette base, une fois par base :

CREATE EXTENSION pg_stat_statements;

Si l'extension est créée et la bibliothèque non chargée, la vue existe et ne collecte rien. Ce sont deux états distincts, et l'outil dit lequel.

SQL Server

Il vient de sys.dm_exec_query_stats, regroupé par query_hash, qui est la forme de la requête. Le texte affiché est celui d'une de ses exécutions, avec ses littéraux, pas une forme avec des marqueurs. Le lire demande l'autorisation VIEW SERVER STATE ; sans elle, la vue affiche l'erreur du serveur. Réinitialiser les statistiques n'apparaît pas : vider ce résumé serait DBCC FREEPROCCACHE, qui jette les plans de tout le serveur, et cela ne se fait pas d'ici.

Le résumé est celui du serveur entier, donc les privilèges comptent : là où votre utilisateur ne peut pas lire les requêtes des autres, le serveur renvoie la ligne sans le texte. Quand cela arrive, c'est dit ici avec le nombre —combien de formes de plus vous ne pouvez pas lire—, ce qui est très différent d'une liste vide.

Réinitialiser les statistiques remet ces compteurs à zéro pour tout le serveur, pas pour votre session : cela touche quiconque regarde le même résumé, et c'est irréversible.

Oracle

Il vient de V$SQL, groupé par FORCE_MATCHING_SIGNATURE : deux requêtes qui ne diffèrent que par un littéral forment une ligne, et le texte affiché est celui de l'une d'elles. Les instructions sans cette signature —les blocs PL/SQL, le DDL— sont groupées par leur SQL_ID. Le résumé n'applique pas le seuil, et le maximum est celui de l'exécution moyenne la plus lente parmi celles qu'il groupe : le cache ne garde pas chaque exécution. Réinitialiser les statistiques n'apparaît pas, ni Vider le journal dans Entrées : les deux reviendraient à vider le cache partagé de tout le serveur.

ClickHouse

Il vient de system.query_log, regroupé par normalized_query_hash : deux requêtes qui ne diffèrent que par un littéral font une seule ligne, et le texte affiché est celui de l'une d'elles. Réinitialiser les statistiques vide cette même table, donc emporte aussi les exécutions, et la confirmation le dit.

Mots-clés : résumé, par instruction, performance_schema, pg_stat_statements, normalisée, privilèges

Du journal au Profileur

Le journal dit quelle requête est lente ; pour savoir pourquoi, on l'envoie à l'éditeur et on la profile là-bas.

Où le trouver : Requêtes lentes › menu contextuel › Envoyer à l'éditeur

Le journal dit quelle requête est lente. Pour savoir pourquoi, la requête doit être réexécutée, et c'est votre décision — pas celle d'une liste qui s'actualise toutes les dix secondes.

Depuis une ligne, par son menu contextuel ou en ouvrant sa fiche, Envoyer à l'éditeur dépose la requête dans l'Éditeur SQL, dans un onglet, sans l'exécuter. Là, vous décidez quoi en faire.

MySQLMariaDBAuroraClickHouseOracle

L'exécuter et appuyer sur Profiler pour voir la répartition par phase, ou demander son plan au moteur avec EXPLAIN visuel.

PostgreSQLSQL Server

Demander son plan au moteur avec EXPLAIN visuel. Profiler, la répartition par phase, n’apparaît pas dans l’éditeur : ce moteur ne la fournit pas.

TiDB

Demander son plan au moteur avec EXPLAIN visuel. Profiler, la répartition par phase, n'apparaît pas dans l'éditeur : TiDB ne l'a pas.

Avant d'exécuter ce qu'apporte une ligne, rappelez-vous que le texte est celui qu'a exécuté un autre client, avec ses paramètres et contre la base qu'il avait ouverte.

MySQLMariaDBAuroraPostgreSQLTiDB

Et du résumé par instruction, ce qui arrive est la forme normalisée, avec des marqueurs au lieu des valeurs : il faut mettre vos propres valeurs avant de l'exécuter.

SQL ServerClickHouseOracle

Du résumé par instruction, ce qui arrive est le texte d'une de ses exécutions, avec les valeurs de celle-ci : la ligne représente toutes celles de la même forme.

Mots-clés : profiler, profileur, éditeur, explain, plan, envoyer à l'éditeur

Vider le journal et remettre le résumé à zéro

Ce que chaque bouton supprime sur le serveur et avec quels moteurs il apparaît.

Où le trouver : Espace de travail › Outils › Requêtes lentes

Deux boutons suppriment ce que le serveur a enregistré, et aucun ne s’annule.

- Vider le journal, dans Entrées, supprime les exécutions enregistrées.
- Réinitialiser les statistiques, dans Par instruction, remet à zéro le résumé de tout le serveur, pas seulement le vôtre.

Les deux confirmations disent combien de lignes partiront, comptées sur le serveur avant de demander, et passent par la protection de l’étiquette d’environnement. Elles n’apparaissent que là où le moteur le permet et où la session peut écrire.

MySQLMariaDBAurora

Avec MySQL, MariaDB et Aurora, les deux boutons sont disponibles.

PostgreSQL

Avec PostgreSQL, il n’y a que la remise à zéro des statistiques : les exécutions sont le journal du serveur, qu’un client n’efface pas ; c’est le serveur qui le fait tourner.

ClickHouse

Avec ClickHouse, les deux sont disponibles, et remettre les statistiques à zéro supprime aussi les exécutions, car c’est la même table.

Oracle

Avec Oracle, aucun des deux n’est proposé.

SQL Server

Avec SQL Server, Vider le journal arrête et redémarre la session, ce qui vide la mémoire ; si elle écrit dans un fichier, elle passe à un nouveau, et l’ancien reste dans le répertoire de données du serveur sans être relu. Réinitialiser les statistiques n’apparaît pas : ce serait DBCC FREEPROCCACHE, qui jette les plans de tout le serveur.

TiDB

Avec TiDB, aucun n’est proposé : le journal est un fichier de chaque nœud, et le résumé se renouvelle seul à chaque fenêtre.

Mots-clés : vider, effacer, réinitialiser, statistiques, requêtes lentes, résumé