Statistiques des requêtes

Spanner fournit des tables intégrées qui conservent de nombreuses statistiques sur les requêtes et les instructions LMD qui ont utilisé le plus de processeur, ainsi que sur toutes les requêtes de manière agrégée (y compris les requêtes de flux de modifications).

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.

Utilisation du processeur regroupée par requête

Les tables ci-dessous suivent les requêtes ayant entraîné le plus haut niveau d'utilisation du processeur pendant une période donnée :

  • SPANNER_SYS.QUERY_STATS_TOP_MINUTE : requêtes émises durant des intervalles d'une minute
  • SPANNER_SYS.QUERY_STATS_TOP_10MINUTE : requêtes émises durant des intervalles de 10 minutes
  • SPANNER_SYS.QUERY_STATS_TOP_HOUR : requêtes émises durant des intervalles d'une heure

Ces tables ont les propriétés suivantes :

  • Chaque table contient les données correspondant à des intervalles de temps sans chevauchement de la durée spécifiée par le nom de la table.

  • Les intervalles sont définis selon l'heure réelle. Les intervalles d'une minute se terminent toutes les minutes, les intervalles de 10 minutes se terminent toutes les 10 minutes à partir de l'heure et les intervalles d'une heure se terminent toutes les heures.

    Par exemple, à 11:59:30, les intervalles les plus récents disponibles pour les requêtes SQL sont les suivants :

    • 1 minute : 11:58:00 – 11:58:59
    • 10 minutes : 11:40:00 – 11:49:59
    • 1 heure : 10:00:00 – 10:59:59
  • Spanner regroupe les statistiques en fonction du texte de la requête SQL. Si une requête utilise des paramètres de requête, Spanner regroupe toutes les exécutions de cette requête sur une ligne. Si la requête utilise des littéraux de chaîne, Spanner ne regroupe les statistiques que si le texte complet de la requête est identique. Lorsqu'un texte diffère, chaque requête apparaît sur une ligne distincte. Pour le LMD par lot, Spanner normalise le lot en dédupliquant les instructions identiques consécutives avant de générer l'empreinte.

  • Si un tag de requête est présent, FPRINT est le hachage de ce tag. Sinon, il s'agit du hachage de la valeur TEXT.

  • Chaque ligne contient les statistiques de toutes les exécutions d'une requête SQL particulière pour laquelle Spanner capture des statistiques pendant l'intervalle spécifié.

  • Si Spanner n'est pas en mesure de stocker toutes les requêtes exécutées pendant l'intervalle, le système donne la priorité à celles qui ont le plus utilisé le processeur au cours de l'intervalle spécifié.

  • Les requêtes suivies incluent celles qui ont abouti, qui ont échoué ou qui ont été annulées par l'utilisateur.

  • Un sous-ensemble de statistiques est spécifique aux requêtes qui ont été exécutées mais qui n'ont pas abouti :

    • Nombre d'exécutions et latence moyenne en secondes pour toutes les requêtes ayant échoué.

    • Nombre d'exécutions pour les requêtes ayant expiré.

    • Nombre d'exécutions de requêtes annulées par l'utilisateur ou ayant échoué en raison de problèmes de connectivité réseau.

  • Toutes les colonnes des tables peuvent avoir une valeur nulle.

Schéma de la table

Nom de la colonne Type Description
INTERVAL_END TIMESTAMP Fin de l'intervalle de temps au cours duquel les exécutions de requête retenues ont eu lieu
REQUEST_TAG STRING Tag de requête facultatif pour cette opération de requête. Pour en savoir plus sur l'utilisation des tags, consultez la page Résoudre les problèmes liés aux tags de requête.
QUERY_TYPE STRING Indique si une requête est de type PARTITIONED_QUERY ou QUERY. Un PARTITIONED_QUERY est une requête avec un partitionToken obtenu à partir de l'API PartitionQuery. Toutes les autres requêtes et instructions LMD sont indiquées par le type de requête QUERY. Les statistiques de requête pour le LMD partitionné ne sont pas acceptées.
TEXT STRING Texte de requête SQL, tronqué à environ 64 Ko

Les statistiques de plusieurs requêtes contenant la même chaîne de tag sont regroupées sur une seule ligne, l'élément REQUEST_TAG correspondant à cette chaîne de tag. Seul le texte de l'une de ces requêtes est affiché dans ce champ, tronqué à environ 64 Ko. Pour le LMD par lot, l'ensemble d'instructions SQL est aplati en une seule ligne, concaténée à l'aide d'un délimiteur de point-virgule. Les textes SQL identiques consécutifs sont dédupliqués avant d'être tronqués.
TEXT_TRUNCATED BOOL Valeur indiquant si le texte de la requête a été tronqué
TEXT_FINGERPRINT INT64 Hachage de la valeur REQUEST_TAG, le cas échéant. Dans le cas contraire, hachage de la valeur TEXT.
EXECUTION_COUNT INT64 Nombre de fois où Spanner a vu la requête au cours de l'intervalle.
AVG_LATENCY_SECONDS FLOAT64 Durée moyenne, en secondes, de chaque exécution de la requête au sein de la base de données, à l'exclusion du temps d'encodage et de transmission de l'ensemble de résultats ainsi que de la surcharge
AVG_ROWS FLOAT64 Nombre moyen de lignes renvoyées par la requête
AVG_BYTES FLOAT64 Nombre moyen d'octets de données renvoyés par la requête, à l'exclusion de la surcharge liée à l'encodage de la transmission
AVG_ROWS_SCANNED FLOAT64 Nombre moyen de lignes analysées par la requête, à l'exclusion des valeurs supprimées
AVG_CPU_SECONDS FLOAT64 Nombre moyen de secondes de temps CPU consacrées par Spanner sur l'ensemble des opérations requises pour exécuter la requête.
ALL_FAILED_EXECUTION_COUNT INT64 Nombre de fois où la requête a échoué pendant l'intervalle.
ALL_FAILED_AVG_LATENCY_SECONDS FLOAT64 Durée moyenne, en secondes, de chaque exécution de la requête ayant échoué dans la base de données, à l'exclusion du temps d'encodage et de transmission de l'ensemble de résultats ainsi que de la surcharge
CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT INT64 Nombre de fois où la requête a été annulée par l'utilisateur ou a échoué en raison d'une interruption de la connexion réseau pendant l'intervalle.
TIMED_OUT_EXECUTION_COUNT INT64 Nombre de fois où la requête a expiré pendant l'intervalle.
AVG_BYTES_WRITTEN FLOAT64 Nombre moyen d'octets écrits par l'instruction.
AVG_ROWS_WRITTEN FLOAT64 Nombre moyen de lignes modifiées par l'instruction.
STATEMENT_COUNT INT64 Somme des instructions agrégées dans cette entrée. Pour les requêtes standards et le LMD, cette valeur correspond au nombre d'exécutions. Pour les instructions LMD par lot, Spanner capture le nombre d'instructions dans le lot.
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 Nombre de fois où la requête a été exécutée dans le cadre d'une transaction en lecture/écriture. Cette colonne vous aide à déterminer si vous pouvez éviter les conflits de verrouillage en déplaçant la requête vers une transaction en lecture seule.
LATENCY_DISTRIBUTION ARRAY<STRUCT>

Un histogramme du temps d'exécution de la requête. Les valeurs sont mesurées en secondes.

Le tableau contient un seul élément et présente le type suivant :
ARRAY<STRUCT<
  COUNT INT64,
  MEAN FLOAT64,
  SUM_OF_SQUARED_DEVIATION FLOAT64,
  NUM_FINITE_BUCKETS INT64,
  GROWTH_FACTOR FLOAT64,
  SCALE FLOAT64,
  BUCKET_COUNTS ARRAY<INT64>>>

Pour en savoir plus sur les valeurs, consultez Distribution.

Pour calculer la latence en centile à partir de la distribution, utilisez la fonction SPANNER_SYS.DISTRIBUTION_PERCENTILE(distribution, n FLOAT64), qui renvoie le nième centile estimé. Pour obtenir un exemple connexe, consultez la section Trouver la latence du 99e centile pour les requêtes.

Pour en savoir plus, consultez Centiles et métriques de valeur de distribution.

AVG_MEMORY_PEAK_USAGE_BYTES FLOAT64

Lors de l'exécution d'une requête distribuée, pic moyen d'utilisation de la mémoire (en octets).

Utilisez cette statistique pour identifier les requêtes ou les tailles de données de table susceptibles d'atteindre les limites de mémoire.

AVG_MEMORY_USAGE_PERCENTAGE FLOAT64

Lors de l'exécution d'une requête distribuée, l'utilisation moyenne de mémoire requise (en pourcentage de la limite de mémoire autorisée pour cette requête).

Cette statistique ne suit que la mémoire nécessaire à l'exécution de la requête. Certains opérateurs utilisent de la mémoire de mise en mémoire tampon supplémentaire pour améliorer les performances. La mémoire de mise en mémoire tampon supplémentaire utilisée est visible dans le plan de requête, mais n'est pas utilisée pour calculer la AVG_MEMORY_USAGE_PERCENTAGE, car la mémoire de mise en mémoire tampon est utilisée pour l'optimisation et n'est pas requise.

Utilisez cette statistique pour identifier les requêtes qui approchent de la limite d'utilisation de la mémoire et qui risquent d'échouer en cas d'augmentation de la taille des données. Pour réduire le risque d'échec de la requête, consultez les bonnes pratiques SQL pour optimiser ces requêtes, ou divisez la requête en éléments qui lisent moins de données.

AVG_QUERY_PLAN_CREATION_TIME_SECS FLOAT64

Temps CPU moyen en secondes consacré à la compilation des requêtes, y compris à la création de leur environnement d'exécution.

Si la valeur de cette colonne est élevée, utilisez des requêtes paramétrées.

AVG_FILESYSTEM_DELAY_SECS FLOAT64

Temps moyen passé par la requête à lire à partir du système de fichiers ou à être bloqué en entrée/sortie (E/S).

Utilisez cette statistique pour identifier la latence élevée potentielle causée par les E/S du système de fichiers. Pour atténuer les effets de cet abandon, ajoutez un index ou une clause STORING (GoogleSQL) ou INCLUDE (PostgreSQL) à un index existant.

AVG_REMOTE_SERVER_CALLS FLOAT64

Nombre moyen d&#RPC;appels de serveur distants effectués par la requête.

Utilisez cette statistique pour déterminer si différentes requêtes qui analysent le même nombre de lignes présentent un nombre très différent de RPC. La requête avec une valeur RPC plus élevée peut tirer parti de l'ajout d'un index ou d'une clause STORING (GoogleSQL) ou INCLUDE (PostgreSQL) à un index existant.

AVG_ROWS_SPOOLED FLOAT64

Nombre moyen de lignes écrites sur un disque temporaire (non en mémoire) par l'instruction de requête.

Utilisez cette statistique pour identifier les requêtes à latence potentiellement élevée qui sont gourmandes en mémoire et ne peuvent pas être exécutées en mémoire. Pour résoudre ce problème, modifiez l'ordre JOIN ou ajoutez un index qui fournit un SORT requis.

EXECUTION_COUNT, AVG_LATENCY_SECONDS et LATENCY_DISTRIBUTION pour les requêtes ayant échoué incluent les requêtes qui ont échoué en raison d'une syntaxe incorrecte ou qui ont rencontré une erreur temporaire, mais qui ont abouti lors d'une nouvelle tentative.

Statistiques globales

Il existe également des tables qui effectuent le suivi des données globales de toutes les requêtes pour lesquelles Spanner a enregistré des statistiques sur une période spécifique:

  • SPANNER_SYS.QUERY_STATS_TOTAL_MINUTE : requêtes émises durant des intervalles d'une minute
  • SPANNER_SYS.QUERY_STATS_TOTAL_10MINUTE : requêtes émises durant des intervalles de 10 minutes
  • SPANNER_SYS.QUERY_STATS_TOTAL_HOUR : requêtes émises durant des intervalles d'une heure

Ces tables ont les propriétés suivantes :

  • Chaque table contient les données correspondant à des intervalles de temps sans chevauchement de la durée spécifiée par le nom de la table.

  • Les intervalles sont définis selon l'heure réelle. Les intervalles d'une minute se terminent toutes les minutes, les intervalles de 10 minutes se terminent toutes les 10 minutes à partir de l'heure et les intervalles d'une heure se terminent toutes les heures.

    Par exemple, à 11:59:30, les intervalles les plus récents disponibles pour les requêtes SQL sont les suivants :

    • 1 minute : 11:58:00 – 11:58:59
    • 10 minutes : 11:40:00 – 11:49:59
    • 1 heure : 10:00:00 – 10:59:59
  • Chaque ligne contient les statistiques globales correspondant à l'ensemble des requêtes exécutées sur la base de données au cours de l'intervalle spécifié. Il n'y a par conséquent qu'une seule ligne par intervalle de temps, qui inclut les requêtes terminées, les requêtes ayant échoué et les requêtes annulées par l'utilisateur.

  • Les statistiques capturées dans les tables TOTAL peuvent inclure des requêtes que Spanner n'a pas capturées dans les tables TOP.

  • Certaines colonnes de ces tables sont présentées en tant que métriques dans Cloud Monitoring. Les métriques exposées sont les suivantes:

    • Nombre d'exécutions de la requête
    • Échecs de requête
    • Latences des requêtes
    • Nombre de lignes renvoyées
    • Nombre de lignes analysées
    • Nombre d'octets renvoyés
    • Temps CPU de la requête

    Pour en savoir plus, consultez la page Métriques Spanner.

Schéma de la table

Nom de la colonne Type Description
INTERVAL_END TIMESTAMP Fin de l'intervalle de temps au cours duquel les exécutions de requête retenues ont eu lieu
EXECUTION_COUNT INT64 Nombre de fois où Spanner a vu la requête au cours de l'intervalle de temps.
AVG_LATENCY_SECONDS FLOAT64 Durée moyenne, en secondes, de chaque exécution de la requête au sein de la base de données, à l'exclusion du temps d'encodage et de transmission de l'ensemble de résultats ainsi que de la surcharge
AVG_ROWS FLOAT64 Nombre moyen de lignes renvoyées par la requête
AVG_BYTES FLOAT64 Nombre moyen d'octets de données renvoyés par la requête, à l'exclusion de la surcharge liée à l'encodage de la transmission
AVG_ROWS_SCANNED FLOAT64 Nombre moyen de lignes analysées par la requête, à l'exclusion des valeurs supprimées
AVG_CPU_SECONDS FLOAT64 Nombre moyen de secondes de temps CPU consacrées par Spanner sur l'ensemble des opérations requises pour exécuter la requête.
ALL_FAILED_EXECUTION_COUNT INT64 Nombre de fois où la requête a échoué pendant l'intervalle.
ALL_FAILED_AVG_LATENCY_SECONDS FLOAT64 Durée moyenne, en secondes, de chaque exécution de la requête ayant échoué dans la base de données, à l'exclusion du temps d'encodage et de transmission de l'ensemble de résultats ainsi que de la surcharge
CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT INT64 Nombre de fois où la requête a été annulée par l'utilisateur ou a échoué en raison d'une interruption de la connexion réseau pendant l'intervalle.
TIMED_OUT_EXECUTION_COUNT INT64 Nombre de fois où la requête a expiré pendant l'intervalle.
AVG_BYTES_WRITTEN FLOAT64 Nombre moyen d'octets écrits par l'instruction.
AVG_ROWS_WRITTEN FLOAT64 Nombre moyen de lignes modifiées par l'instruction.
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 Nombre de fois où des requêtes ont été exécutées dans le cadre de transactions en lecture/écriture. Cette colonne vous aide à déterminer si vous pouvez éviter les conflits de verrouillage en déplaçant certaines requêtes vers des transactions en lecture seule.
LATENCY_DISTRIBUTION ARRAY<STRUCT>

Un histogramme du temps d'exécution pour l'ensemble des requêtes. Les valeurs sont mesurées en secondes.

Spécifiez le tableau comme suit :
ARRAY<STRUCT<
  COUNT INT64,
  MEAN FLOAT64,
  SUM_OF_SQUARED_DEVIATION FLOAT64,
  NUM_FINITE_BUCKETS INT64,
  GROWTH_FACTOR FLOAT64,
  SCALE FLOAT64,
  BUCKET_COUNTS ARRAY<INT64>>>

Pour en savoir plus sur les valeurs, consultez Distribution.

Pour calculer la latence en centile à partir de la distribution, utilisez la fonction SPANNER_SYS.DISTRIBUTION_PERCENTILE(distribution, n FLOAT64), qui renvoie le nième centile estimé. Pour obtenir un exemple connexe, consultez la section Trouver la latence du 99e centile pour les requêtes.

Pour en savoir plus, consultez Centiles et métriques de valeur de distribution.

Conservation des données

Spanner conserve au minimum les données de chaque table pendant les périodes suivantes:

  • SPANNER_SYS.QUERY_STATS_TOP_MINUTE et SPANNER_SYS.QUERY_STATS_TOTAL_MINUTE : intervalles couvrant les six heures précédentes

  • SPANNER_SYS.QUERY_STATS_TOP_10MINUTE et SPANNER_SYS.QUERY_STATS_TOTAL_10MINUTE : intervalles couvrant les quatre derniers jours.

  • SPANNER_SYS.QUERY_STATS_TOP_HOUR et SPANNER_SYS.QUERY_STATS_TOTAL_HOUR : intervalles couvrant les 30 derniers jours.

Exemples de requêtes

Cette section présente plusieurs exemples d'instructions SQL permettant d'extraire des statistiques sur les requêtes. Vous pouvez exécuter ces instructions SQL à l'aide des bibliothèques clientes, de Google Cloud CLI ou de la console Google Cloud.

Lister les statistiques de base pour chaque requête sur une période donnée

La requête suivante renvoie les données brutes correspondant aux principales requêtes exécutées au cours de la minute précédente :

SELECT text,
       request_tag,
       interval_end,
       execution_count,
       avg_latency_seconds,
       avg_rows,
       avg_bytes,
       avg_rows_scanned,
       avg_cpu_seconds
FROM spanner_sys.query_stats_top_minute
ORDER BY interval_end DESC;

Lister les requêtes entraînant le plus haut niveau d'utilisation du processeur

La requête suivante renvoie les requêtes qui ont entraîné le niveau le plus élevé d'utilisation du processeur au cours de l'heure précédente :

SELECT text,
       request_tag,
       execution_count AS count,
       avg_latency_seconds AS latency,
       avg_cpu_seconds AS cpu,
       execution_count * avg_cpu_seconds AS total_cpu
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY total_cpu DESC;

Déterminer le nombre total d'exécutions pour une période donnée

La requête suivante renvoie le nombre total de requêtes exécutées au cours du dernier intervalle complet d'une minute :

SELECT interval_end,
       execution_count
FROM spanner_sys.query_stats_total_minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_minute);

Déterminer la latence moyenne d'une requête

La requête suivante renvoie la latence moyenne d'une requête donnée :

SELECT avg_latency_seconds
FROM spanner_sys.query_stats_top_hour
WHERE text LIKE "SELECT x FROM table WHERE x=@foo;";

Déterminer la latence au 99e centile des requêtes

La requête suivante renvoie le 99e centile de la durée d'exécution de toutes les requêtes exécutées au cours des 10 dernières minutes:

SELECT interval_end, avg_latency_seconds, SPANNER_SYS.DISTRIBUTION_PERCENTILE(latency_distribution[OFFSET(0)], 99.0)
  AS percentile_latency
FROM spanner_sys.query_stats_total_10minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_total_10minute)
ORDER BY interval_end;

La comparaison de la latence moyenne à la latence du 99e centile permet d'identifier les requêtes aberrantes possibles avec des temps d'exécution élevés.

Identifier les requêtes qui analysent le plus de données

Vous pouvez utiliser le nombre de lignes analysées par une requête comme mesure de la quantité de données analysées par cette dernière. La requête suivante renvoie le nombre de lignes analysées par les requêtes exécutées au cours de l'heure précédente :

SELECT text,
       execution_count,
       avg_rows_scanned
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY avg_rows_scanned DESC;

Trouver les énoncés qui ont écrit le plus de données

Vous pouvez utiliser le nombre de lignes écrites (ou d'octets écrits) par LMD comme mesure de la quantité de données modifiées par la requête. La requête suivante renvoie le nombre de lignes écrites par des instructions LMD exécutées au cours de l'heure précédente:

SELECT text,
       execution_count,
       avg_rows_written
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY avg_rows_written DESC;

Utilisation totale du processeur pour toutes les requêtes

La requête suivante renvoie le nombre d'heures d'utilisation du CPU au cours de l'heure précédente :

SELECT (avg_cpu_seconds * execution_count / 60 / 60)
  AS total_cpu_hours
FROM spanner_sys.query_stats_total_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_total_hour);

Lister les requêtes qui ont échoué sur une période donnée

La requête suivante renvoie les données brutes, y compris le nombre d'exécutions et la latence moyenne des requêtes ayant échoué pour les principales requêtes au cours de la minute précédente :

SELECT text,
       request_tag,
       interval_end,
       execution_count,
       all_failed_execution_count,
       all_failed_avg_latency_seconds,
       avg_latency_seconds,
       avg_rows,
       avg_bytes,
       avg_rows_scanned,
       avg_cpu_seconds
FROM spanner_sys.query_stats_top_minute
WHERE all_failed_execution_count > 0
ORDER BY interval_end;

Trouver le nombre total d'erreurs sur une période donnée

La requête suivante renvoie le nombre total de requêtes qui n'ont pas pu être exécutées au cours du dernier intervalle complet d'une minute.

SELECT interval_end,
       all_failed_execution_count
FROM spanner_sys.query_stats_total_minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_minute)
ORDER BY interval_end;

Lister les requêtes dont le délai d'expiration est le plus élevé

La requête suivante renvoie les requêtes qui ont présenté le délai avant expiration le plus élevé au cours de l'heure précédente.

SELECT text,
       execution_count AS count,
       timed_out_execution_count AS timeout_count,
       avg_latency_seconds AS latency,
       avg_cpu_seconds AS cpu,
       execution_count * avg_cpu_seconds AS total_cpu
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY timed_out_execution_count DESC;

Trouver la latence moyenne des exécutions ayant réussi et échoué pour une requête

La requête suivante renvoie la latence moyenne combinée, la latence moyenne pour des exécutions réussies et la latence moyenne pour les exécutions ayant échoué pour une requête spécifique.

SELECT avg_latency_seconds AS combined_avg_latency,
       all_failed_avg_latency_seconds AS failed_execution_latency,
       ( avg_latency_seconds * execution_count -
         all_failed_avg_latency_seconds * all_failed_execution_count
       ) / (
       execution_count - all_failed_execution_count ) AS success_execution_latency
FROM   spanner_sys.query_stats_top_hour
WHERE  text LIKE "select x from table where x=@foo;";

Résoudre les problèmes d'utilisation élevée du processeur ou de latence élevée des requêtes à l'aide de statistiques sur les requêtes

Les statistiques de requête sont utiles lorsque vous devez examiner une utilisation élevée du processeur sur votre base de données Spanner ou lorsque vous essayez simplement de comprendre les formes de requêtes qui sollicitent fortement le processeur de votre base de données. L'inspection des requêtes qui utilisent des quantités importantes de ressources de base de données offre aux utilisateurs de Spanner un moyen potentiel de réduire les coûts opérationnels et d'améliorer les latences générales du système.

Vous pouvez examiner les requêtes problématiques dans votre base de données à l'aide du code SQL ou du tableau de bord Insights sur les requêtes. Les articles suivants expliquent comment examiner ces requêtes à l'aide de code SQL.

Bien que l'exemple suivant porte sur l'utilisation du processeur, des étapes similaires peuvent être suivies pour résoudre les problèmes de latence élevée des requêtes et identifier les requêtes présentant les latences les plus élevées. Il vous suffit de sélectionner des intervalles de temps et des requêtes par latence plutôt que par utilisation du processeur.

Sélectionnez une période à examiner

Commencez votre évaluation en recherchant une heure à laquelle votre application a commencé à subir une utilisation élevée du processeur. (par exemple, si le problème a commencé à se produire vers 17h le 24 juillet 2020 UTC).

Recueillir des statistiques sur les requêtes pour la période sélectionnée

Après avoir sélectionné une période pour démarrer notre enquête, nous examinerons les statistiques collectées dans la table QUERY_STATS_TOTAL_10MINUTE autour de cette période. Les résultats de cette requête peuvent indiquer l'évolution du processeur et d'autres statistiques de requête au cours de cette période.

La requête suivante renvoie les statistiques de requête agrégées de 16:30 à 17:30 UTC inclus. Nous utilisons ROUND dans notre requête pour limiter le nombre de décimales à des fins d'affichage.

SELECT interval_end,
       execution_count AS count,
       ROUND(avg_latency_seconds,2) AS latency,
       ROUND(avg_rows,2) AS rows_returned,
       ROUND(avg_bytes,2) AS bytes,
       ROUND(avg_rows_scanned,2) AS rows_scanned,
       ROUND(avg_cpu_seconds,3) AS avg_cpu
FROM spanner_sys.query_stats_total_10minute
WHERE
  interval_end >= "2020-07-24T16:30:00Z"
  AND interval_end <= "2020-07-24T17:30:00Z"
ORDER BY interval_end;

L'exécution de la requête a produit les résultats suivants.

interval_end nombre latence rows_returned bytes rows_scanned avg_cpu
2020-07-24T16:30:00Z 6 0,06 5,00 536,00 16,67 0,035
2020-07-24T16:40:00Z 55 0,02 0.22 25,29 0.22 0,004
2020-07-24T16:50:00Z 102 0,02 0,30 33,35 0,30 0,004
2020-07-24T17:00:00Z 154 1.06 4.42 486.33 7792208.12 4.633
2020-07-24T17:10:00Z 94 0,02 1,68 106,84 1,68 0,006
2020-07-24T17:20:00Z 110 0,02 0,38 34,60 0,38 0,005
2020-07-24T17:30:00Z 47 0,02 0.23 24,96 0.23 0,004

Dans le tableau précédent, nous constatons que le temps CPU moyen, c'est-à-dire la colonne avg_cpu de la table des résultats, est le plus élevé dans les intervalles en surbrillance se terminant à 17h. Nous constatons également un nombre beaucoup plus élevé de lignes analysées en moyenne. Cela indique que des requêtes plus coûteuses ont été exécutées entre 16h50 et 17h00. Choisissez cet intervalle pour en savoir plus à l'étape suivante.

Identifier les requêtes qui entraînent une utilisation élevée du processeur

Maintenant qu'un intervalle de temps d'examen est sélectionné, nous allons interroger la table QUERY_STATS_TOP_10MINUTE. Les résultats de cette requête peuvent vous aider à identifier les requêtes qui sollicitent beaucoup le processeur.

SELECT text_fingerprint AS fingerprint,
       execution_count AS count,
       ROUND(avg_latency_seconds,2) AS latency,
       ROUND(avg_cpu_seconds,3) AS cpu,
       ROUND(execution_count * avg_cpu_seconds,3) AS total_cpu
FROM spanner_sys.query_stats_top_10MINUTE
WHERE
  interval_end = "2020-07-24T17:00:00Z"
ORDER BY total_cpu DESC;

L'exécution de cette requête produit les résultats suivants.

fingerprint nombre latence cpu total_cpu
5505124206529314852 30 3.88 17.635 529.039
1697951036096498470 10 4.49 18.388 183.882
2295109096748351518 1 0,33 0,048 0,048
11618299167612903606 1 0,25 0,021 0,021
10302798842433860499 1 0,04 0.006 0.006
123771704548746223 1 0,04 0.006 0.006
4216063638051261350 1 0,04 0.006 0.006
3654744714919476398 1 0,04 0.006 0.006
2999453161628434990 1 0,04 0.006 0.006
823179738756093706 1 0,02 0,005 0.0056

Les deux principales requêtes, mises en évidence dans le tableau des résultats, présentent des anomalies en termes de processeur moyen, de latence, de nombre d'exécutions et de processeur total. Examinez la première requête affichée dans ces résultats.

Comparer les exécutions de requêtes au fil du temps

Après avoir affiné l'investigation, nous pouvons nous concentrer sur la table QUERY_STATS_TOP_MINUTE. En comparant les exécutions au fil du temps d'une requête particulière, nous pouvons rechercher des corrélations entre le nombre de lignes ou d'octets renvoyés, ou le nombre de lignes analysées et l'élévation du processeur ou de la latence. Un écart peut indiquer une non-uniformité des données. Un nombre systématiquement élevé de lignes analysées peut indiquer un manque d'index appropriés ou un ordre de jointure non optimal.

Examinez la requête qui présente l'utilisation moyenne de processeur la plus élevée et la latence la plus élevée en exécutant l'instruction suivante qui filtre le text_fingerprint de cette requête.

SELECT interval_end,
       ROUND(avg_latency_seconds,2) AS latency,
       avg_rows AS rows_returned,
       avg_bytes AS bytes_returned,
       avg_rows_scanned AS rows_scanned,
       ROUND(avg_cpu_seconds,3) AS cpu,
FROM spanner_sys.query_stats_top_minute
WHERE text_fingerprint = 5505124206529314852
ORDER BY interval_end DESC;

L'exécution de cette requête renvoie les résultats suivants.

interval_end latence rows_returned bytes_returned rows_scanned cpu
2020-07-24T17:00:00Z 4.55 21 2365 30000000 19,255
2020-07-24T16:00:00Z 3,62 21 2365 30000000 17,255
2020-07-24T15:00:00Z 4,37 21 2365 30000000 18,350
2020-07-24T14:00:00Z 4,02 21 2365 30000000 17,748
2020-07-24T13:00:00Z 3.12 21 2365 30000000 16,380
2020-07-24T12:00:00Z 3,45 21 2365 30000000 15,476
2020-07-24T11:00:00Z 4,94 21 2365 30000000 22,611
2020-07-24T10:00:00Z 6,48 21 2365 30000000 21,265
2020-07-24T09:00:00Z 0.23 21 2365 5 0,040
2020-07-24T08:00:00Z 0,04 21 2365 5 0,021
2020-07-24T07:00:00Z 0.09 21 2365 5 0,030

En examinant les résultats précédents, nous constatons que le nombre de lignes analysées, l'utilisation du processeur et la latence ont tous considérablement changé vers 9h00. Pour comprendre pourquoi ces nombres ont considérablement augmenté, nous allons examiner le texte de la requête et voir si des modifications du schéma sont susceptibles d'avoir affecté la requête.

Utilisez la requête suivante pour récupérer le texte de la requête que nous examinons.

SELECT text,
       text_truncated
FROM spanner_sys.query_stats_top_hour
WHERE text_fingerprint = 5505124206529314852
LIMIT 1;

Cette commande renvoie le résultat suivant.

text text_truncated
sélectionnez * dans les ordres où o_custkey = 36901; false

En examinant le texte de la requête renvoyé, nous constatons qu'elle filtre sur un champ appelé o_custkey. Il s'agit d'une colonne non-clé de la table orders. En l'occurrence, cette colonne contenait un index qui a été abandonné vers 9h. Cela explique la variation du coût de cette requête. Nous pouvons ajouter de nouveau l'index ou, si la requête n'est pas souvent exécutée, décider de ne pas l'avoir et accepter le coût de lecture plus élevé.

Notre analyse s'est concentrée jusqu'à présent sur les requêtes qui ont abouti et nous avons trouvé une raison pour laquelle la base de données rencontre une certaine dégradation des performances. À l'étape suivante, nous nous concentrerons sur les requêtes ayant échoué ou qui ont été annulées, et nous verrons comment examiner ces données pour obtenir plus d'insights.

Examiner les requêtes ayant échoué

Les requêtes qui ne se terminent pas correctement consomment toujours des ressources avant leur expiration, leur annulation ou leur échec. Spanner suit le nombre d'exécutions et les ressources consommées par les requêtes ayant échoué, ainsi que les requêtes ayant abouti.

Pour vérifier si les requêtes ayant échoué contribuent de manière significative à l'utilisation du système, nous pouvons d'abord vérifier le nombre de requêtes ayant échoué dans l'intervalle de temps qui vous intéresse.

SELECT interval_end,
       all_failed_execution_count AS failed_count,
       all_failed_avg_latency_seconds AS latency
FROM spanner_sys.query_stats_total_minute
WHERE
  interval_end >= "2020-07-24T16:50:00Z"
  AND interval_end <= "2020-07-24T17:00:00Z"
ORDER BY interval_end;
interval_end failed_count latence
2020-07-24T16:52:00Z 1 15,211391
2020-07-24T16:53:00Z 3 58,312232

Pour une investigation plus détaillée, nous pouvons rechercher les requêtes les plus susceptibles d'échouer à l'aide de la requête suivante.

SELECT interval_end,
       text_fingerprint,
       execution_count,
       avg_latency_seconds AS avg_latency,
       all_failed_execution_count AS failed_count,
       all_failed_avg_latency_seconds AS failed_latency,
       cancelled_or_disconnected_execution_count AS cancel_count,
       timed_out_execution_count AS to_count
FROM spanner_sys.query_stats_top_minute
WHERE all_failed_execution_count > 0
ORDER BY interval_end;
interval_end text_fingerprint execution_count failed_count cancel_count to_count
2020-07-24T16:52:00Z 5505124206529314852 3 1 1 0
2020-07-24T16:53:00Z 1697951036096498470 2 1 1 0
2020-07-24T16:53:00Z 5505124206529314852 5 2 1 1

Comme le montre le tableau précédent, la requête avec l'empreinte 5505124206529314852 a échoué plusieurs fois sur différents intervalles de temps. Compte tenu d'un tel schéma d'échecs, il est intéressant de comparer la latence des exécutions réussies et échouées.

SELECT interval_end,
       avg_latency_seconds AS combined_avg_latency,
       all_failed_avg_latency_seconds AS failed_execution_latency,
       ( avg_latency_seconds * execution_count -
         all_failed_avg_latency_seconds * all_failed_execution_count
       ) / (
       execution_count - all_failed_execution_count ) AS success_execution_latency
FROM   spanner_sys.query_stats_top_hour
WHERE  text_fingerprint = 5505124206529314852;
interval_end combined_avg_latency failed_execution_latency success_execution_latency
2020-07-24T17:00:00Z 3,880420 13,830709 2,774832

Appliquer les bonnes pratiques

Après avoir identifié une requête pour l'optimisation, nous pouvons examiner le profil de requête et essayer d'optimiser la requête à l'aide des bonnes pratiques SQL.

Étapes suivantes