Planes de ejecución de consultas

Descripción general

En esta página, se proporcionan conceptos sobre los planes de ejecución de consultas y cómo los usan Spanner para realizar consultas en un entorno distribuido Para saber cómo hacerlo a fin de recuperar un plan de ejecución para una consulta específica usando el En la consola de Google Cloud, consulta Comprende cómo se ejecuta Spanner del usuario. También puedes visualizar planes de consultas históricas de muestra y comparar el el rendimiento de una consulta en el tiempo para determinadas consultas. Para obtener más información, consulta Planes de consulta de muestra.

Spanner usa instrucciones de SQL declarativas para consultar sus bases de datos. Las instrucciones de SQL definen qué quiere el usuario sin especificar cómo obtener los resultados. Un plan de ejecución de consultas es el conjunto de pasos para saber cómo obtener los resultados. Para una instrucción de SQL determinada, puede haber varias formas de obtener los resultados. El optimizador de consultas de Spanner evalúa diferentes planes de ejecución y elige el que considere más eficiente. Luego, Spanner usa el plan de ejecución para recuperar los resultados.

De forma conceptual, un plan de ejecución es un árbol de operadores relacionales. Cada operador lee filas de sus entradas y produce filas de salida. El resultado del operador en la raíz de la ejecución se muestra como resultado de la consulta de SQL.

Por ejemplo:

SELECT s.SongName FROM Songs AS s;

Mediante la consulta anterior, se obtiene como resultado un plan de ejecución de consultas que se puede visualizar de la siguiente manera:

Ejemplo del plan de ejecución de consultas

Las consultas y los planes de ejecución en esta página se basan en el siguiente esquema de base de datos:

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
  BirthDate  DATE
) PRIMARY KEY(SingerId);

CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);

CREATE TABLE Albums (
  SingerId        INT64 NOT NULL,
  AlbumId         INT64 NOT NULL,
  AlbumTitle      STRING(MAX),
  MarketingBudget INT64
) PRIMARY KEY(SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);

CREATE TABLE Songs (
  SingerId  INT64 NOT NULL,
  AlbumId   INT64 NOT NULL,
  TrackId   INT64 NOT NULL,
  SongName  STRING(MAX),
  Duration  INT64,
  SongGenre STRING(25)
) PRIMARY KEY(SingerId, AlbumId, TrackId),
  INTERLEAVE IN PARENT Albums ON DELETE CASCADE;

CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC), INTERLEAVE IN Albums;

CREATE INDEX SongsBySongName ON Songs(SongName);

CREATE TABLE Concerts (
  VenueId      INT64 NOT NULL,
  SingerId     INT64 NOT NULL,
  ConcertDate  DATE NOT NULL,
  BeginTime    TIMESTAMP,
  EndTime      TIMESTAMP,
  TicketPrices ARRAY<INT64>
) PRIMARY KEY(VenueId, SingerId, ConcertDate);

Puedes usar las siguientes declaraciones del lenguaje de manipulación de datos (DML) para agregar datos a estas tablas:

INSERT INTO Singers (SingerId, FirstName, LastName, BirthDate)
VALUES (1, "Marc", "Richards", "1970-09-03"),
       (2, "Catalina", "Smith", "1990-08-17"),
       (3, "Alice", "Trentor", "1991-10-02"),
       (4, "Lea", "Martin", "1991-11-09"),
       (5, "David", "Lomond", "1977-01-29");

INSERT INTO Albums (SingerId, AlbumId, AlbumTitle)
VALUES (1, 1, "Total Junk"),
       (1, 2, "Go, Go, Go"),
       (2, 1, "Green"),
       (2, 2, "Forever Hold Your Peace"),
       (2, 3, "Terrified"),
       (3, 1, "Nothing To Do With Me"),
       (4, 1, "Play");

INSERT INTO Songs (SingerId, AlbumId, TrackId, SongName, Duration, SongGenre)
VALUES (2, 1, 1, "Let's Get Back Together", 182, "COUNTRY"),
       (2, 1, 2, "Starting Again", 156, "ROCK"),
       (2, 1, 3, "I Knew You Were Magic", 294, "BLUES"),
       (2, 1, 4, "42", 185, "CLASSICAL"),
       (2, 1, 5, "Blue", 238, "BLUES"),
       (2, 1, 6, "Nothing Is The Same", 303, "BLUES"),
       (2, 1, 7, "The Second Time", 255, "ROCK"),
       (2, 3, 1, "Fight Story", 194, "ROCK"),
       (3, 1, 1, "Not About The Guitar", 278, "BLUES");

Obtener planes de ejecución eficientes es un desafío porque Spanner divide los datos en divisiones. Las divisiones se pueden mover de forma independiente unas de otras y pueden asignarse a servidores distintos, que pueden estar en diferentes ubicaciones físicas. Para evaluar los planes de ejecución sobre los datos distribuidos, Spanner usa la ejecución en función de lo siguiente:

  • la ejecución local de subplanes en servidores que contienen los datos
  • la organización y agregación de varias ejecuciones remotas con una fuerte reducción de la distribución

Spanner usa el operador primitivo distributed union, junto con sus variantes distributed cross apply y distributed outer apply, para habilitar este modelo.

Planes de consulta de muestra

Los planes de consulta de muestra de Spanner te permiten ver muestras de datos históricos y comparar el rendimiento de una consulta a lo largo del tiempo. No todas las consultas tener planes de consulta de muestra disponibles. Solo las consultas que consumen más CPU pueden que se muestrearán. La retención de datos para las muestras de planes de consultas de Spanner es 30 días. Puedes encontrar muestras de planes de consultas en la página Estadísticas de consultas de la consola de Google Cloud. Para obtener instrucciones, consulta Visualiza los planes de consulta de muestra.

La anatomía de un plan de consultas de muestra es la misma que la de una ejecución de consultas normal. de recuperación ante desastres. Para obtener más información sobre cómo entender los planes visuales y usarlos para depurar tus consultas, consulta Un recorrido por el visualizador del plan de consultas.

Casos de uso comunes para planes de consultas de muestra:

Estos son algunos casos de uso comunes para los planes de consultas de muestra:

Si el rendimiento de una consulta muestra una diferencia significativa en el tiempo o si si quieres mejorar el rendimiento de una consulta, consulta las prácticas recomendadas sobre SQL crear instrucciones de consulta optimizadas que ayuden a Spanner a encontrar planes de ejecución eficientes.

El ciclo de una consulta

Una consulta en SQL en Spanner se compila primero en un plan de ejecución. luego, se envía a un servidor root inicial para su ejecución. El servidor raíz es elegidas para minimizar el número de saltos para alcanzar los datos que se consultan. El servidor raíz, luego:

  • inicia la ejecución remota de los subplanes (si es necesario)
  • espera los resultados de las ejecuciones remotas
  • maneja los pasos de ejecución local restantes, como la agregación de resultados
  • muestra los resultados de la consulta

Los servidores remotos que reciben un subplan actúan como un servidor “raíz” para su subplan y siguen el mismo modelo que el servidor raíz superior. El resultado es un árbol de ejecuciones remotas. De forma conceptual, la ejecución de la consulta fluye de arriba abajo y los resultados de la consulta se muestran de abajo arriba. En el siguiente diagrama, se muestra este patrón:

Plan de consultas conceptual

En los siguientes ejemplos, se ilustra este patrón con más detalle.

Consultas agregadas

Una consulta agregada implementa consultas GROUP BY.

Por ejemplo:

SELECT s.SingerId, COUNT(*) AS SongCount
FROM Songs AS s
WHERE s.SingerId < 100
GROUP BY s.SingerId;

Los resultados de la consulta anterior son los siguientes:

+----------+-----------+
| SingerId | SongCount |
+----------+-----------+
|        3 |         1 |
|        2 |         8 |
+----------+-----------+

De manera conceptual, este es el plan de ejecución:

Plan de ejecución de consultas agregadas

Spanner envía el plan de ejecución a un servidor raíz que coordina la ejecución de la consulta y realiza la distribución remota de los subplanes.

Este plan de ejecución comienza con una unión distribuida, que distribuye subplanes a servidores remotos cuyas divisiones cumplan con SingerId < 100. Después del análisis en divisiones individuales, el operador de agregación de transmisión agrega filas para obtener los recuentos de cada SingerId. Luego, el operador de serialización de resultados serializa el resultado. Por último, la unión distribuida combina todos los resultados y devuelve los resultados de la consulta.

Para obtener más información sobre los agregados, consulta la página sobre el operador de agregación.

Consultas de unión ubicadas en el mismo lugar

Las tablas intercaladas se almacenan de forma física con sus filas de tablas relacionadas ubicadas en el mismo lugar. Una unión ubicada en el mismo lugar es una unión entre tablas intercaladas. Las uniones ubicadas en el mismo lugar pueden ofrecer beneficios de rendimiento en comparación con las uniones que requieren índices o reversión de uniones.

Por ejemplo:

SELECT al.AlbumTitle, so.SongName
FROM Albums AS al, Songs AS so
WHERE al.SingerId = so.SingerId AND al.AlbumId = so.AlbumId;

(En esta consulta, se da por sentado que Songs está intercalado en Albums).

Los resultados de la consulta anterior son los siguientes:

+-----------------------+--------------------------+
| AlbumTitle            | SongName                 |
+-----------------------+--------------------------+
| Nothing To Do With Me | Not About The Guitar     |
| Green                 | The Second Time          |
| Green                 | Starting Again           |
| Green                 | Nothing Is The Same      |
| Green                 | Let's Get Back Together  |
| Green                 | I Knew You Were Magic    |
| Green                 | Blue                     |
| Green                 | 42                       |
| Terrified             | Fight Story              |
+-----------------------+--------------------------+

Este es el plan de ejecución:

Plan de ejecución de consultas de uniones ubicadas en el mismo lugar

Este plan de ejecución comienza con una unión distribuida, que distribuye los subplanes a servidores remotos que tienen divisiones de la tabla Albums. Como Songs es una tabla intercalada de Albums, cada servidor remoto puede ejecutar todo el subplan en cada servidor remoto sin requerir una unión para en un servidor diferente.

Los subplanes contienen una aplicación cruzada. Cada aplicación cruzada realiza una tabla. analizar en la tabla Albums para recuperar SingerId, AlbumId y AlbumTitle La aplicación cruzada asigna el resultado del análisis de la tabla al resultado de un análisis de índice en el índice SongsBySingerAlbumSongNameDesc, sujeto a un filtro del SingerId en el índice que coincide con el SingerId del resultado del análisis de la tabla. Cada aplicación cruzada envía sus resultados a un resultado de serialización. que serializa los datos AlbumTitle y SongName y muestra resultados a las uniones distribuidas locales. Los agregados de la unión distribuida resultados de las uniones distribuidas locales y los muestra como el resultado de la consulta.

Consultas de índices y de reversiones de uniones

En el ejemplo anterior, se usó una unión en dos tablas, una intercalada en la otra. Los planes de ejecución son más complejos y menos eficaces cuando dos tablas o una tabla y un índice no están intercalados.

Considera un índice creado con el siguiente comando:

CREATE INDEX SongsBySongName ON Songs(SongName)

Usa este índice en la siguiente consulta:

SELECT s.SongName, s.Duration
FROM Songs@{force_index=SongsBySongName} AS s
WHERE STARTS_WITH(s.SongName, "B");

Los resultados de la consulta anterior son los siguientes:

+----------+----------+
| SongName | Duration |
+----------+----------+
| Blue     |      238 |
+----------+----------+

Este es el plan de ejecución:

Plan de ejecución de consultas de reversiones de uniones

El plan de ejecución resultante es complicado porque el índice SongsBySongName no contiene la columna Duration. Para obtener el valor Duration, haz lo siguiente: Spanner necesita revertir la unión de los resultados indexados a la tabla. Songs Esta es una unión, pero no se ubica en el mismo lugar porque la tabla Songs y el índice global SongsBySongName no están intercalados. La ejecución resultante el plan es más complejo que el ejemplo de unión ubicada en el mismo lugar porque Spanner realiza optimizaciones para acelerar la ejecución si los datos no están ubicadas en el mismo lugar.

El operador superior es una aplicación cruzada distribuida. Este lado de entrada de este operador son lotes de filas del índice SongsBySongName que satisfacen el predicado STARTS_WITH(s.SongName, "B"). La aplicación distribuida cruzada asigna los lotes a los servidores remotos, que tienen divisiones con los datos Duration. Los servidores remotos usan un análisis de tabla para recuperar la columna Duration. El análisis de la tabla usa el filtro Condition:($Songs_key_TrackId' = $batched_Songs_key_TrackId), que une TrackId de la tabla Songs a El TrackId de las filas que se agruparon en lotes del índice SongsBySongName.

Los resultados se agregan a la respuesta final de la consulta. A su vez, el lado de entrada de la aplicación distribuida cruzada contiene un par de unión distribuida y unión distribuida local para evaluar las filas del índice que cumplen con el predicado STARTS_WITH.

Considera hacer una consulta un poco diferente, que no seleccione la columna s.Duration:

SELECT s.SongName
FROM Songs@{force_index=SongsBySongName} AS s
WHERE STARTS_WITH(s.SongName, "B");

Esta consulta puede aprovechar al máximo el índice como se muestra en este plan de ejecución:

Plan de ejecución de consultas más simple

El plan de ejecución no necesita una reversión de la unión, porque todas las columnas que solicita la consulta están presentes en el índice.

¿Qué sigue?