Statistiques les plus anciennes requêtes actives

Les requêtes actives les plus anciennes, également appelées requêtes les plus longues, répertorient les requêtes actuellement actives dans votre base de données, triées en fonction de leur durée d'exécution. L'analyse de ces requêtes permet d'identifier les causes des problèmes de latence du système et d'utilisation intensive du processeur au fur et à mesure qu'ils se produisent.

Spanner fournit une table intégrée, SPANNER_SYS.OLDEST_ACTIVE_QUERIES, qui répertorie les requêtes en cours d'exécution, y compris celles contenant des instructions LMD, triées par heure de début et par ordre croissant. Les requêtes de flux de modifications ne sont pas incluses.

Si un grand nombre de requêtes sont en cours d'exécution, les résultats peuvent être limités à un sous-ensemble du nombre total de requêtes en raison des contraintes de mémoire appliquées par le système sur la collecte de ces données. Par conséquent, Spanner fournit une table supplémentaire, SPANNER_SYS.ACTIVE_QUERIES_SUMMARY, qui affiche des statistiques récapitulatives pour toutes les requêtes actives (à l'exception des requêtes de flux de modifications). Vous pouvez récupérer des informations dans ces deux tables intégrées à l'aide d'instructions SQL.

Dans cet article, nous allons décrire les deux tables, afficher des exemples de requêtes utilisant ces tables et, pour finir, nous vous montrerons comment les utiliser pour limiter les problèmes causés par les requêtes actives.

Qui peut en bénéficier ?

Les données SPANNER_SYS ne sont disponibles que via des interfaces SQL. Exemple :

Les autres méthodes de lecture unique fournies par Spanner ne sont pas compatibles avec SPANNER_SYS.

OLDEST_ACTIVE_QUERIES

SPANNER_SYS.OLDEST_ACTIVE_QUERIES renvoie la liste des requêtes actives triées par heure de début. Si un grand nombre de requêtes est en cours d'exécution, les résultats peuvent être limités à un sous-ensemble du nombre total de requêtes en raison des contraintes de mémoire appliquées par Spanner à la collecte de ces données. Pour afficher les statistiques récapitulatives de toutes les requêtes actives, consultez ACTIVE_QUERIES_SUMMARY.

Schéma de la table

Nom de la colonne Type Description
START_TIME TIMESTAMP Heure de début de la requête.
TEXT_FINGERPRINT INT64 L'empreinte est le hachage des opérations impliquées dans la transaction.
TEXT STRING Texte de l'instruction de requête.
TEXT_TRUNCATED BOOL "True" si le texte de la requête dans le champ TEXT est tronqué. Sinon, la valeur est "false".
SESSION_ID STRING ID de la session qui exécute la requête. La suppression de l'ID de session annule la requête.

Exemples de requêtes

Vous pouvez exécuter les exemples d'instructions SQL suivants à l'aide des bibliothèques clientes, de la Google Cloud CLI ou de la console Google Cloud.

Répertorier les requêtes en cours les plus anciennes

La requête suivante renvoie la liste des requêtes les plus anciennes exécutées en fonction de l'heure de début de la requête.

SELECT start_time,
       text_fingerprint,
       text,
       text_truncated,
       session_id
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC;
start_time text_fingerprint text text_truncated session_id
2020-07-18T07:52:28.225877Z -3426560921851907385 SELECT a.SingerId, a.AlbumId, a.TrackId, b.SingerId as b_id, b.AlbumId as b_albumid, b.TrackId as b_trackId FROM Songs as a CROSS JOIN Songs as b; false ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw
2020-07-18T07:54:08.622081Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; False ACjbPvaF3yKiNfxXFod2LPoFaXjKR759Bw1o34206vv0t7eOrD3wxZhu8U6ohQ
2020-07-18T07:54:08.631744Z -105437553161169030 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE a.SingerId > 7 LIMIT 1000000; false ACjbPvanq3MesDNT98t64KdKAz3TlDZoCC-zgW-FJn91cJHuczQ_cOFN_Hdflw
2020-07-18T07:54:08.720011Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; false ACjbPvYIE2QHkhnmMXuAGpB4inK7yMnQjmYgQ9FoygKNaB5KCXu7Sf7f9aghYw
2020-07-18T07:54:08.731006Z 6561582859583559006 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE a.SingerId > 10 LIMIT 1000000; false ACjbPvYNZ06N2YyvwV0YMlSRBNDtXBqZEK-iAAyPFnFcTmshPvzWkhr034ud7w

Répertorier les 2 premières requêtes en cours les plus anciennes

Petite variante de la requête précédente, cet exemple renvoie les deux premières requêtes en cours les plus anciennes triées selon l'heure de début de la requête.

SELECT start_time,
       text_fingerprint,
       text,
       text_truncated,
       session_id
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC LIMIT 2;
Sortie de la requête
start_time text_fingerprint text text_truncated session_id
2020-07-18T07:52:28.225877Z -3426560921851907385 SELECT a.SingerId, a.AlbumId, a.TrackId, b.SingerId as b_id, b.AlbumId as b_albumid, b.TrackId as b_trackId FROM Songs as a CROSS JOIN Songs as b; false ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw
2020-07-18T07:54:08.622081Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; False ACjbPvaF3yKiNfxXFod2LPoFaXjKR759Bw1o34206vv0t7eOrD3wxZhu8U6ohQ

ACTIVE_QUERIES_SUMMARY

Comme son nom l'indique, la table intégrée, SPANNER_SYS.ACTIVE_QUERIES_SUMMARY, affiche des statistiques récapitulatives pour toutes les requêtes actives. Comme indiqué dans le schéma suivant, les requêtes sont regroupées par âge en trois buckets (ou compteurs) datant de plus d'une seconde, de plus de 10 secondes et de plus de 100 secondes.

Schéma des tables

Nom de la colonne Type Description
ACTIVE_COUNT INT64 Nombre total de requêtes en cours d'exécution.
OLDEST_START_TIME TIMESTAMP Limite supérieure de l'heure de début de la requête en cours la plus ancienne.
COUNT_OLDER_THAN_1S INT64 Nombre de requêtes de plus d'une seconde.
COUNT_OLDER_THAN_10S INT64 Nombre de requêtes de plus de 10 secondes.
COUNT_OLDER_THAN_100S INT64 Nombre de requêtes de plus de 100 secondes.

Une requête peut être comptabilisée dans plusieurs de ces buckets. Par exemple, si une requête a été exécutée pendant 12 secondes, elle est comptabilisée dans COUNT_OLDER_THAN_1S et COUNT_OLDER_THAN_10S, car elle remplit les deux critères.

Exemples de requêtes

Vous pouvez exécuter les exemples d'instructions SQL suivants à l'aide des bibliothèques clientes, de gcloud spanner ou de la console Google Cloud.

Récupérer un résumé des requêtes actives

La requête suivante renvoie des statistiques récapitulatives sur les requêtes en cours.

SELECT active_count,
       oldest_start_time,
       count_older_than_1s,
       count_older_than_10s,
       count_older_than_100s
FROM spanner_sys.active_queries_summary;
Sortie de la requête
active_count oldest_start_time count_older_than_1s count_older_than_10s count_older_than_100s
22 2020-07-18T07:52:28.225877Z 21 21 1

Limites

Bien que l'objectif soit de vous fournir les insights les plus complets possibles, il existe des cas où les requêtes ne sont pas incluses dans les données renvoyées dans ces tables.

  • Les requêtes LMD (UPDATE/INSERT/DELETE) ne sont pas incluses si elles se trouvent dans la phase Apply mutations.

  • Une requête n'est pas incluse si elle est en cours de redémarrage en raison d'une erreur temporaire.

  • Les requêtes provenant de serveurs surchargés ou qui ne répondent pas ne sont pas prises en compte.

  • OLDEST_ACTIVE_QUERIES ne peut pas être utilisé dans une transaction en lecture/écriture. Même dans une transaction en lecture seule, l'horodatage de la transaction est ignoré et elle renvoie toujours les données actuelles au moment de son exécution. Dans de rares cas, elle peut renvoyer une erreur ABORTED avec des résultats partiels. Dans ce cas, supprimez les résultats partiels et relancez la requête.

Utiliser les données des requêtes actives pour résoudre les problèmes d'utilisation élevée du processeur

Les statistiques sur les requêtes et les statistiques sur les transactions fournissent des informations utiles pour résoudre les problèmes de latence dans une base de données Spanner. Ces outils fournissent des informations sur les requêtes déjà effectuées. Cependant, il est parfois nécessaire de savoir ce qui est en cours d'exécution dans le système. Prenons l'exemple du scénario dans lequel l'utilisation du processeur est assez élevée et que vous souhaitez répondre aux questions suivantes.

  • Combien de requêtes sont exécutées actuellement ?
  • Quelles sont ces requêtes ?
  • Combien de requêtes sont exécutées depuis longtemps, c'est-à-dire plus de 100 secondes ?
  • Quelle session exécute la requête ?

Avec les réponses aux questions précédentes, vous pouvez décider d'effectuer l'action suivante.

  • Supprimer la session qui exécute la requête pour une résolution immédiate.
  • Améliorer les performances des requêtes en ajoutant un index.
  • Réduisez la fréquence de la requête si elle est associée à une tâche périodique en arrière-plan.
  • Identifiez l'utilisateur ou le composant émettant la requête qui pourrait ne pas être autorisé à l'exécuter.

Dans ce tutoriel, nous examinons nos requêtes actives et déterminons l'action à effectuer, le cas échéant.

Récupérer un résumé des requêtes actuellement actives

Dans notre exemple de scénario, nous constatons que l'utilisation du processeur est supérieure à la normale. Nous allons donc exécuter la requête suivante pour renvoyer un résumé des requêtes actives.

SELECT active_count,
       oldest_start_time,
       count_older_than_1s,
       count_older_than_10s,
       count_older_than_100s
FROM spanner_sys.active_queries_summary;

La requête donne les résultats suivants.

active_count oldest_start_time count_older_than_1s count_older_than_10s count_older_than_100s
22 2020-07-18T07:52:28.225877Z 21 21 1

Il semble qu'une seule requête en cours s'exécute pendant plus de 100 secondes. Ce résultat est inhabituel pour notre base de données et nous souhaitons l'étudier plus en détail.

Récupérer une liste de requêtes actives

Nous avons déterminé lors de l'étape précédente que nous exécutions une requête pendant plus de 100 secondes. Pour aller plus loin, nous exécutons la requête suivante pour renvoyer des informations supplémentaires sur les cinq requêtes en cours les plus anciennes.

SELECT start_time,
       text_fingerprint,
       text,
       text_truncated,
       session_id
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC LIMIT 5;

Dans cet exemple, nous avons exécuté la requête le 18 juillet 2020 à environ 0h54m18s PDT et récupéré les résultats suivants. (Vous devrez peut-être faire défiler la page horizontalement pour voir l'intégralité du résultat.)

start_time text_fingerprint text text_truncated session_id
2020-07-18T07:52:28.225877Z -3426560921851907385 SELECT a.SingerId, a.AlbumId, a.TrackId, b.SingerId as b_id, b.AlbumId as b_albumid, b.TrackId as b_trackId FROM Songs as a CROSS JOIN Songs as b; False ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw
2020-07-18T07:54:08.622081Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; False ACjbPvaF3yKiNfxXFod2LPoFaXjKR759Bw1o34206vv0t7eOrD3wxZhu8U6ohQ
2020-07-18T07:54:08.631744Z -105437553161169030 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE a.SingerId > 7 LIMIT 1000000; false ACjbPvanq3MesDNT98t64KdKAz3TlDZoCC-zgW-FJn91cJHuczQ_cOFN_Hdflw
2020-07-18T07:54:08.720011Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; false ACjbPvYIE2QHkhnmMXuAGpB4inK7yMnQjmYgQ9FoygKNaB5KCXu7Sf7f9aghYw
2020-07-18T07:54:08.731006Z 6561582859583559006 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE a.SingerId > 10 LIMIT 1000000; false ACjbPvYNZ06N2YyvwV0YMlSRBNDtXBqZEK-iAAyPFnFcTmshPvzWkhr034ud7w

La requête la plus ancienne (empreinte = -3426560921851907385) est mise en surbrillance dans le tableau. Le service est cher. CROSS JOIN. Nous décidons d'agir.

Annuler une requête onéreuse

Nous avons trouvé une requête exécutant une jointure croisée CROSS JOIN coûteuse. Nous décidons donc de l'annuler. Les résultats de la requête de l'étape précédente comprenaient un session_id, qui correspond à l'ID de la session qui exécute la requête. Nous pouvons donc exécuter la commande gcloud spanner databases sessions delete suivante pour supprimer la session en utilisant cet ID, ce qui annule la requête.

gcloud spanner databases sessions delete\
   ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw \
    --database=singer_db --instance=test-instance

Ce tutoriel explique comment utiliser SPANNER_SYS.OLDEST_ACTIVE_QUERIES et SPANNER_SYS.ACTIVE_QUERIES_SUMMARY pour analyser nos requêtes en cours d'exécution et prendre les mesures nécessaires, le cas échéant, sur toute requête contribuant à une utilisation intensive du processeur. Évidemment, il est toujours plus économique d'éviter les opérations coûteuses et de concevoir un schéma adapté à vos cas d'utilisation. Pour en savoir plus sur la construction d'instructions SQL qui s'exécutent efficacement, consultez la section Bonnes pratiques SQL.

Étapes suivantes