En esta página se describen los detalles sobre los operadores que se usan en los planes de ejecución de consultas de Spanner. Para saber cómo obtener un plan de ejecución de una consulta específica mediante la consola Google Cloud , consulta el artículo Cómo ejecuta Spanner las consultas.
Las consultas y los planes de ejecución de 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 instrucciones del lenguaje de manipulación de datos (DML) para añadir 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");
Operadores de hojas
Un operador hoja es un operador que no tiene elementos secundarios. Los tipos de operadores de hoja son los siguientes:
Desanidación de matriz
Un operador desanidar matriz aplana una matriz de entrada en filas de elementos. Cada fila resultante contiene hasta dos columnas: el valor real de la matriz y, de forma opcional, la posición basada en cero en la matriz.
Por ejemplo, con esta consulta:
SELECT a, b FROM UNNEST([1,2,3]) a WITH OFFSET b;
La consulta aplana la matriz [1,2,3]
de la columna a
y muestra la posición de la matriz en la columna b
.
Estos son los resultados:
a | b |
---|---|
1 | 0 |
2 | 1 |
3 | 2 |
Este es el plan de ejecución:
Generar relación
Un operador generate relation devuelve cero o más filas.
Relación de unidades
La relación de unidad devuelve una fila. Es un caso especial del operador generate relation.
Por ejemplo, con esta consulta:
SELECT 1 + 2 AS Result;
El resultado es el siguiente:
Resultado |
---|
3 |
Este es el plan de ejecución:
Relación vacía
La relación vacía no devuelve ninguna fila. Es un caso especial del operador generate relation.
Por ejemplo, con esta consulta:
SELECT *
FROM albums
LIMIT 0
El resultado es el siguiente:
No hay resultados
Este es el plan de ejecución:
Examinar
Un operador scan devuelve filas analizando una fuente de filas. Estos son los tipos de operadores de búsqueda:
- Análisis de tabla: el análisis se realiza en una tabla.
- Análisis de índice: el análisis se realiza en un índice.
- Análisis por lotes: el análisis se realiza en tablas intermedias creadas por otros operadores relacionales (por ejemplo, una tabla creada por un cross apply distribuido).
Siempre que sea posible, Spanner aplica predicados en las claves como parte de un análisis. Los análisis se ejecutan de forma más eficiente cuando se aplican predicados, ya que no es necesario que lean toda la tabla o el índice. Los predicados aparecen en el plan de ejecución con el formato KeyPredicate: column=value
.
En el peor de los casos, una consulta puede tener que buscar todas las filas de una tabla. Esta situación lleva a un análisis completo y aparece en el plan de ejecución como full scan:
true
.
Por ejemplo, con esta consulta:
SELECT s.lastname
FROM singers@{FORCE_INDEX=SingersByFirstLastName} as s
WHERE s.firstname = 'Catalina';
Estos son los resultados:
LastName |
---|
Smith |
Este es el plan de ejecución:
En el plan de ejecución, el operador distributed union
de nivel superior envía subplanes a servidores remotos. Cada subplan tiene un operador serialize
result y un operador de análisis de índice. El predicado
Key Predicate: FirstName = 'Catalina'
restringe la búsqueda a las filas del índice
SingersByFirstLastname
que tienen FirstName
igual a Catalina
. La salida del análisis de índice se devuelve al operador de resultados de serialización.
Operadores unarios
Un operador unario es un operador que tiene un solo elemento secundario relacional.
Los siguientes operadores son operadores unarios:
- Agregación
- Aplicar mutaciones
- Crear lote
- Compute
- Estructura de cálculo
- DataBlockToRowAdapter
- Filtro
- Filtrar análisis
- Límite
- Unión de divisiones locales
- Asignación de ID aleatorio
- RowToDataBlockAdapter
- Serializar resultado
- Ordenar
- TVF
- Unión
Agregar
Un operador de agregación implementa instrucciones SQL GROUP BY
y funciones de agregación (como COUNT
). La entrada de un operador de agregación se divide lógicamente en grupos organizados en columnas clave (o en un solo grupo si no se incluye GROUP BY
). Para cada grupo, se calculan cero o más agregaciones.
Por ejemplo, con esta consulta:
SELECT s.singerid,
Avg(s.duration) AS average,
Count(*) AS count
FROM songs AS s
GROUP BY singerid;
La consulta agrupa por SingerId
y realiza una agregación AVG
y una agregación COUNT
.
Estos son los resultados:
SingerId | average | recuento |
---|---|---|
3 | 278 | 1 |
2 | 225.875 | 8 |
Este es el plan de ejecución:
Los operadores de agregación pueden ser basados en flujos o basados en hash. El plan de ejecución anterior muestra un agregado basado en secuencias. Los agregados basados en secuencias leen de una entrada ya preordenada (si GROUP BY
está presente) y calculan el grupo sin bloquearse. Los agregados basados en hash crean tablas hash para mantener agregados incrementales de varias filas de entrada simultáneamente. Los agregados basados en secuencias son más rápidos y usan menos memoria que los agregados basados en hash, pero requieren que la entrada esté ordenada (por columnas clave o por índices secundarios).
En los casos distribuidos, un operador de agregación se puede separar en un par local-global. Cada servidor remoto realiza la agregación local en sus filas de entrada y, a continuación, devuelve los resultados al servidor raíz. El servidor raíz realiza la agregación global.
Aplicar mutaciones
Un operador apply mutations aplica las mutaciones de una declaración de manipulación de datos (DML) a la tabla. Es el operador superior de un plan de consulta de una instrucción DML.
Por ejemplo, con esta consulta:
DELETE FROM singers
WHERE firstname = 'Alice';
Estos son los resultados:
4 rows deleted This statement deleted 4 rows and did not return any rows.
Este es el plan de ejecución:
Crear lote
Un operador create batch agrupa sus filas de entrada en una secuencia. Una operación de creación por lotes suele formar parte de una operación de aplicación cruzada distribuida. Las filas de entrada se pueden reordenar durante el proceso por lotes. El número de filas de entrada que se agrupan en cada ejecución del operador de lote varía.
Consulta el operador distributed cross apply para ver un ejemplo de operador de creación de lotes en un plan de ejecución.
Computación
Un operador compute genera una salida leyendo sus filas de entrada y añadiendo una o más columnas adicionales que se calculan mediante expresiones escalares. Consulta el operador UNION ALL para ver un ejemplo de operador de cálculo en un plan de ejecución.
Estructura de Compute
Un operador compute struct crea una variable para una estructura que contiene campos para cada una de las columnas de entrada.
Por ejemplo, con esta consulta:
SELECT FirstName,
ARRAY(SELECT AS STRUCT song.SongName, song.SongGenre
FROM Songs AS song
WHERE song.SingerId = singer.SingerId)
FROM singers AS singer
WHERE singer.SingerId = 3;
Estos son los resultados:
FirstName (Nombre) | Sin especificar |
---|---|
Alice | [["Not About The Guitar","BLUES"]] |
Este es el plan de ejecución:
En el plan de ejecución, el operador de subconsulta de matriz recibe la entrada de un operador de unión distribuida, que a su vez recibe la entrada de un operador de estructura de cálculo. El operador de estructura de cálculo crea una estructura a partir de las columnas SongName
y SongGenre
de la tabla Songs
.
DataBlockToRowAdapter
El optimizador de consultas de Spanner inserta automáticamente un operador DataBlockToRowAdapter
entre un par de operadores que funcionan con métodos de ejecución diferentes. Su entrada es un operador que usa el método de ejecución orientado a lotes y su salida se introduce en un operador que se ejecuta con el método de ejecución orientado a filas. Para obtener más información, consulta el artículo Optimizar la ejecución de consultas.
Filtro
Un operador filter lee todas las filas de su entrada, aplica un predicado escalar en cada fila y, a continuación, devuelve solo las filas que cumplen el predicado.
Por ejemplo, con esta consulta:
SELECT s.lastname
FROM (SELECT s.lastname
FROM singers AS s
LIMIT 3) s
WHERE s.lastname LIKE 'Rich%';
Estos son los resultados:
LastName |
---|
Richards |
Este es el plan de ejecución:
El predicado de los cantantes cuyo apellido empieza por Rich
se implementa como un filtro. La entrada del filtro es la salida de un análisis de índice y la salida del filtro son las filas en las que LastName
empieza por Rich
.
Por motivos de rendimiento, siempre que un filtro se coloque directamente encima de un análisis,
el filtro influye en la forma en que se leen los datos. Por ejemplo, supongamos que tenemos una tabla con la clave k
.
Un filtro con el predicado k = 5
directamente encima de un análisis de la tabla busca filas que coincidan con k = 5
sin leer toda la entrada. De este modo, la consulta se ejecuta de forma más eficiente. En el ejemplo anterior, el operador de filtro solo lee las filas que cumplen el predicado WHERE s.LastName LIKE 'Rich%'
.
Filtrar escaneo
Un operador de análisis de filtro siempre está por encima de un análisis de tabla o índice. Funciona con el análisis para reducir el número de filas leídas de la base de datos y el análisis resultante suele ser más rápido que con un filtro. Spanner aplica el análisis de filtro en determinadas condiciones:
- Condición de búsqueda: la condición de búsqueda se aplica si Spanner puede determinar una fila específica a la que acceder en la tabla. Por lo general, esto ocurre cuando el filtro se aplica a un prefijo de la clave principal. Por ejemplo, si la clave principal consta de
Col1
yCol2
, se puede buscar una cláusulaWHERE
que incluya valores explícitos paraCol1
oCol1
yCol2
. En ese caso, Spanner solo lee datos dentro del intervalo de claves. - Condición residual: cualquier otra condición en la que Spanner pueda evaluar el análisis para limitar la cantidad de datos que se leen.
Por ejemplo, con esta consulta:
SELECT lastname
FROM singers
WHERE singerid = 1
Estos son los resultados:
LastName |
---|
Richards |
Este es el plan de ejecución:
Límite
Un operador limit limita el número de filas devueltas. Un parámetro opcional OFFSET
especifica la fila inicial que se va a devolver. En los casos distribuidos, un operador de límite se puede separar en un par local-global. Cada servidor remoto aplica el límite local a sus filas de salida y, a continuación, devuelve los resultados al servidor raíz. El servidor raíz agrega las filas enviadas por los servidores remotos y, a continuación, aplica el límite global.
Por ejemplo, con esta consulta:
SELECT s.songname
FROM songs AS s
LIMIT 3;
Estos son los resultados:
SongName |
---|
No se trata de la guitarra |
La segunda vez |
Empezar de nuevo |
Este es el plan de ejecución:
El límite local es el límite de cada servidor remoto. El servidor raíz agrega las filas de los servidores remotos y, a continuación, aplica el límite global.
Asignación de ID aleatorio
Un operador de asignación de ID aleatorio genera resultados leyendo sus filas de entrada y añadiendo un número aleatorio a cada fila. Funciona con los operadores Filter
o Sort
para conseguir métodos de muestreo. Los métodos de muestreo admitidos son Bernoulli y Reservoir.
Por ejemplo, la siguiente consulta usa el muestreo de Bernoulli con una frecuencia de muestreo del 10 %.
SELECT s.songname
FROM songs AS s TABLESAMPLE bernoulli (10 PERCENT);
Estos son los resultados:
SongName |
---|
Empezar de nuevo |
Nothing Is The Same |
Tenga en cuenta que, como el resultado es una muestra, puede variar cada vez que se ejecute la consulta, aunque sea la misma.
Este es el plan de ejecución:
En este plan de ejecución, el operador Random Id Assign
recibe su entrada de un operador distributed union, que recibe su entrada de un index scan. El operador devuelve las filas con IDs aleatorios y, a continuación, el operador Filter
aplica un predicado escalar a los IDs aleatorios y devuelve aproximadamente el 10 % de las filas.
En el siguiente ejemplo se usa el muestreo Reservoir con una frecuencia de muestreo de 2 filas.
SELECT s.songname
FROM songs AS s TABLESAMPLE reservoir (2 rows);
Estos son los resultados:
SongName |
---|
I Knew You Were Magic |
La segunda vez |
Tenga en cuenta que, como el resultado es una muestra, puede variar cada vez que se ejecute la consulta, aunque sea la misma.
Este es el plan de ejecución:
En este plan de ejecución, el operador Random Id Assign
recibe su entrada de un operador distributed union, que recibe su entrada de un index scan. El operador devuelve las filas con IDs aleatorios y el operador Sort
aplica el orden a los IDs aleatorios y aplica LIMIT
con dos filas.
Unión de divisiones locales
Un operador local split union busca divisiones de la tabla almacenadas en el servidor local, ejecuta una subconsulta en cada división y, a continuación, crea una unión que combina todos los resultados.
Una unión de divisiones locales aparece en los planes de ejecución que analizan una tabla de emplazamientos. Las colocaciones pueden aumentar el número de divisiones de una tabla, lo que hace que sea más eficiente analizar las divisiones en lotes en función de sus ubicaciones de almacenamiento físico.
Por ejemplo, supongamos que la tabla Singers
usa una clave de emplazamiento para particionar los datos de los cantantes:
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
SingerName STRING(MAX) NOT NULL,
...
Location STRING(MAX) NOT NULL PLACEMENT KEY
) PRIMARY KEY (SingerId);
Ahora, veamos esta consulta:
SELECT BirthDate FROM Singers;
Este es el plan de ejecución:
La unión distribuida envía una subconsulta a cada lote de divisiones almacenadas físicamente en el mismo servidor. En cada servidor, la unión de divisiones local busca divisiones que almacenan datos Singers
, ejecuta la subconsulta en cada división y devuelve los resultados combinados. De esta forma, la unión distribuida y la unión dividida local trabajan juntas para analizar de forma eficiente la tabla Singers
.
Sin una unión dividida local, la unión distribuida enviaría una RPC por división en lugar de por lote de divisiones, lo que daría lugar a viajes de ida y vuelta de RPC redundantes cuando haya más de una división por lote.
RowToDataBlockAdapter
El optimizador de consultas de Spanner inserta automáticamente un operador RowToDataBlockAdapter
entre un par de operadores que funcionan con métodos de ejecución diferentes. Su entrada es un operador que usa el método de ejecución orientado a filas y su salida se introduce en un operador que se ejecuta con el método de ejecución orientado a lotes. Para obtener más información, consulta el artículo Optimizar la ejecución de consultas.
Serializar resultado
Un operador serialize result es un caso especial del operador compute struct que serializa cada fila del resultado final de la consulta para devolverla al cliente.
Por ejemplo, con esta consulta:
SELECT array
(
select as struct so.songname,
so.songgenre
FROM songs AS so
WHERE so.singerid = s.singerid)
FROM singers AS s;
La consulta pide una matriz de SongName
y SongGenre
basada en SingerId
.
Estos son los resultados:
Sin especificar |
---|
[] |
[[Let's Get Back Together, COUNTRY], [Starting Again, ROCK]] |
[[Not About The Guitar, BLUES]] |
[] |
[] |
Este es el plan de ejecución:
El operador de resultados de serialización crea un resultado que contiene, para cada fila de la tabla Singers
, una matriz de pares SongName
y SongGenre
de las canciones del cantante.
Ordenar
Un operador sort lee las filas de entrada, las ordena por columna(s) y devuelve los resultados ordenados.
Por ejemplo, con esta consulta:
SELECT s.songgenre
FROM songs AS s
ORDER BY songgenre;
Estos son los resultados:
SongGenre |
---|
BLUES |
BLUES |
BLUES |
BLUES |
CLÁSICA |
PAÍS |
ROCK |
ROCK |
ROCK |
Este es el plan de ejecución:
En este plan de ejecución, el operador de ordenación recibe sus filas de entrada de un operador de unión distribuida, ordena las filas de entrada y devuelve las filas ordenadas a un operador de serialización de resultados.
Para limitar el número de filas devueltas, un operador de ordenación puede tener opcionalmente los parámetros LIMIT
y OFFSET
. En los casos distribuidos, un operador de ordenación con un operador LIMIT
o OFFSET
se separa en un par local-global. Cada servidor remoto aplica el orden y el límite o el desplazamiento local a sus filas de entrada y, a continuación, devuelve los resultados al servidor raíz. El servidor raíz agrega las filas enviadas por los servidores remotos, las ordena y, a continuación, aplica el límite o el desplazamiento global.
Por ejemplo, con esta consulta:
SELECT s.songgenre
FROM songs AS s
ORDER BY songgenre
LIMIT 3;
Estos son los resultados:
SongGenre |
---|
BLUES |
BLUES |
BLUES |
Este es el plan de ejecución:
El plan de ejecución muestra el límite local de los servidores remotos y el límite global del servidor raíz.
TVF
Un operador de función con valores de tabla genera resultados leyendo sus filas de entrada y aplicando la función especificada. La función puede implementar la asignación y devolver el mismo número de filas que la entrada. También puede ser un generador que devuelva más filas o un filtro que devuelva menos filas.
Por ejemplo, con esta consulta:
SELECT genre,
songname
FROM ml.predict(model genreclassifier, TABLE songs)
Estos son los resultados:
Género | SongName |
---|---|
País | No se trata de la guitarra |
Rock | La segunda vez |
Pop | Empezar de nuevo |
Pop | Nothing Is The Same |
País | Volvamos a estar juntos |
Pop | I Knew You Were Magic |
Electrónica | Azul |
Rock | 42 |
Rock | Fight Story |
Este es el plan de ejecución:
Entrada de unión
Un operador de entrada UNION devuelve resultados a un operador UNION ALL. Consulta el operador UNION ALL para ver un ejemplo de operador de entrada de unión en un plan de ejecución.
Operadores binarios
Un operador binario es un operador que tiene dos elementos secundarios relacionales. Los siguientes operadores son operadores binarios:
- Aplicación cruzada
- Combinación de hash
- Combinación de fusión
- Combinación de hash de difusión push
- Aplicación externa
- Unión recursiva
Aplicación cruzada
Un operador CROSS APPLY ejecuta una consulta de tabla en cada fila extraída por una consulta de otra tabla y devuelve la unión de todas las ejecuciones de las consultas de tabla. Los operadores CROSS APPLY y OUTER APPLY ejecutan un procesamiento orientado a filas, a diferencia de los operadores que ejecutan un procesamiento basado en conjuntos, como HASH JOIN . El operador de aplicación cruzada tiene dos entradas: input y map. El operador CROSS APPLY aplica cada fila del lado de entrada al lado de asignación. El resultado de la aplicación cruzada tiene columnas tanto del lado de la entrada como del lado del mapa.
Por ejemplo, con esta consulta:
SELECT si.firstname,
(SELECT so.songname
FROM songs AS so
WHERE so.singerid = si.singerid
LIMIT 1)
FROM singers AS si;
La consulta pide el nombre de cada cantante, junto con el nombre de solo una de sus canciones.
Estos son los resultados:
FirstName (Nombre) | Sin especificar |
---|---|
Alice | No se trata de la guitarra |
Catalina | Volvamos a estar juntos |
David | NULL |
Lea | NULL |
Marc | NULL |
La primera columna se rellena con datos de la tabla Singers
y la segunda, con datos de la tabla Songs
. En los casos en los que había un SingerId
en la tabla Singers
, pero no había ningún SingerId
coincidente en la tabla Songs
, la segunda columna contiene NULL
.
Este es el plan de ejecución:
El nodo de nivel superior es un operador de unión distribuida. El operador de unión distribuida distribuye subplanes a servidores remotos. El subplan contiene un operador serialize result que calcula el nombre del cantante y el nombre de una de sus canciones, y serializa cada fila del resultado.
El operador de resultados de serialización recibe su entrada de un operador de aplicación cruzada.
El lado de entrada del operador de aplicación cruzada es un examen de la tabla Singers
.
El lado del mapa de la operación de aplicación cruzada contiene lo siguiente (de arriba abajo):
- Un operador de agregación que devuelve
Songs.SongName
. - Un operador limit que limita el número de canciones devueltas a una por cantante.
- Un análisis del índice
SongsBySingerAlbumSongNameDesc
.
El operador CROSS APPLY asigna cada fila del lado de entrada a una fila del lado de asignación que tiene el mismo SingerId
. El resultado del operador de aplicación cruzada es el valor FirstName
de la fila de entrada y el valor SongName
de la fila del mapa.
El valor de SongName
es NULL
si no hay ninguna fila de mapa que coincida con SingerId
. El operador UNION distribuido situado en la parte superior del plan de ejecución combina todas las filas de salida de los servidores remotos y las devuelve como resultados de la consulta.
Combinación hash
Un operador de combinación hash es una implementación basada en hash de las combinaciones SQL. Las combinaciones hash ejecutan el procesamiento basado en conjuntos. El operador de unión de hash lee las filas de la entrada marcada como compilación y las inserta en una tabla de hash en función de una condición de unión. A continuación, el operador de unión de hash lee las filas de la entrada marcada como sondeo. Por cada fila que lee de la entrada de la prueba, el operador de unión de hash busca filas coincidentes en la tabla de hash. El operador de unión de hash devuelve las filas coincidentes como resultado.
Por ejemplo, con esta consulta:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=hash_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
Estos son los resultados:
AlbumTitle | SongName |
---|---|
Nothing To Do With Me | No se trata de la guitarra |
Verde | La segunda vez |
Verde | Empezar de nuevo |
Verde | Nothing Is The Same |
Verde | Volvamos a estar juntos |
Verde | I Knew You Were Magic |
Verde | Azul |
Verde | 42 |
Aterrorizado | Fight Story |
Este es el plan de ejecución:
En el plan de ejecución, build es una unión distribuida que distribuye exploraciones en la tabla Albums
. Probe es un operador de unión distribuida que distribuye análisis en el índice SongsBySingerAlbumSongNameDesc
.
El operador de combinación de hash lee todas las filas del lado de compilación. Cada fila de compilación se coloca en una tabla hash en función de las columnas de la condición a.SingerId =
s.SingerId AND a.AlbumId = s.AlbumId
. A continuación, el operador de unión hash lee todas las filas del lado de la comprobación. Por cada fila de sondeo, el operador de unión hash busca coincidencias en la tabla hash. El operador de combinación hash devuelve las coincidencias resultantes.
Las coincidencias resultantes en la tabla hash también se pueden filtrar por una condición residual antes de que se devuelvan. (Un ejemplo de dónde aparecen las condiciones residuales es en las uniones de desigualdad). Los planes de ejecución de combinaciones hash pueden ser complejos debido a la gestión de la memoria y a las variantes de combinación. El algoritmo principal de combinación hash se adapta para gestionar las variantes de combinación interna, semi, anti y externa.
Combinación por fusión
Un operador de combinación de fusión es una implementación basada en la fusión de la combinación SQL. Ambos lados de la unión producen filas ordenadas por las columnas usadas en la condición de unión. La combinación de fusión consume ambos flujos de entrada simultáneamente y genera filas cuando se cumple la condición de combinación. Si las entradas no se ordenan originalmente como es necesario, el optimizador añade operadores Sort
explícitos al plan.
El optimizador no selecciona automáticamente combinación por fusión. Para usar este operador, define el método de unión como MERGE_JOIN
en la sugerencia de consulta, como se muestra en el siguiente ejemplo:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=merge_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
Estos son los resultados:
AlbumTitle | SongName |
---|---|
Verde | La segunda vez |
Verde | Empezar de nuevo |
Verde | Nothing Is The Same |
Verde | Volvamos a estar juntos |
Verde | I Knew You Were Magic |
Verde | Azul |
Verde | 42 |
Aterrorizado | Fight Story |
Nothing To Do With Me | No se trata de la guitarra |
Este es el plan de ejecución:
En este plan de ejecución, la combinación de fusión se distribuye de forma que la combinación se ejecute donde se encuentren los datos. Esto también permite que la combinación de fusión de este ejemplo funcione sin introducir operadores de ordenación adicionales, ya que ambas lecturas de tabla ya están ordenadas por SingerId
y AlbumId
, que es la condición de combinación. En este plan, el análisis del lado izquierdo de la tabla Albums
avanza cuando su SingerId
y AlbumId
son comparativamente menores que el par SingerId_1
y AlbumId_1
del análisis del índice SongsBySingerAlbumSongNameDesc
del lado derecho.
Del mismo modo, el lado derecho avanza siempre que sea inferior al lado izquierdo. Esta fusión avanzada sigue buscando equivalencias para que se puedan devolver las coincidencias resultantes.
Veamos otro ejemplo de combinación por fusión con la siguiente consulta:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=merge_join} songs AS s
ON a.albumid = s.albumid;
Se obtienen los siguientes resultados:
AlbumTitle | SongName |
---|---|
Total Junk | La segunda vez |
Total Junk | Empezar de nuevo |
Total Junk | Nothing Is The Same |
Total Junk | Volvamos a estar juntos |
Total Junk | I Knew You Were Magic |
Total Junk | Azul |
Total Junk | 42 |
Total Junk | No se trata de la guitarra |
Verde | La segunda vez |
Verde | Empezar de nuevo |
Verde | Nothing Is The Same |
Verde | Volvamos a estar juntos |
Verde | I Knew You Were Magic |
Verde | Azul |
Verde | 42 |
Verde | No se trata de la guitarra |
Nothing To Do With Me | La segunda vez |
Nothing To Do With Me | Empezar de nuevo |
Nothing To Do With Me | Nothing Is The Same |
Nothing To Do With Me | Volvamos a estar juntos |
Nothing To Do With Me | I Knew You Were Magic |
Nothing To Do With Me | Azul |
Nothing To Do With Me | 42 |
Nothing To Do With Me | No se trata de la guitarra |
Reproducir | La segunda vez |
Reproducir | Empezar de nuevo |
Reproducir | Nothing Is The Same |
Reproducir | Volvamos a estar juntos |
Reproducir | I Knew You Were Magic |
Reproducir | Azul |
Reproducir | 42 |
Reproducir | No se trata de la guitarra |
Aterrorizado | Fight Story |
Este es el plan de ejecución:
En el plan de ejecución anterior, el optimizador de consultas ha introducido operadores Sort
adicionales para conseguir las propiedades necesarias para que se ejecute la combinación de fusión. La condición JOIN
de la consulta de este ejemplo solo se aplica a AlbumId
, que no es la forma en que se almacenan los datos, por lo que se debe añadir una ordenación. El motor de consultas admite un algoritmo de combinación distribuida, lo que permite que la ordenación se realice de forma local en lugar de global, lo que distribuye y paraleliza el coste de la CPU.
Las coincidencias resultantes también se pueden filtrar por una condición residual antes de que se devuelvan. (Un ejemplo de dónde aparecen las condiciones residuales es en las combinaciones de no igualdad). Los planes de ejecución de combinación de fusión pueden ser complejos debido a los requisitos de ordenación adicionales. El algoritmo principal de combinación de fusión se adapta para gestionar las variantes de combinación interna, semi, anti y externa.
Unión de hash de emisión push
Un operador de combinación hash de difusión push es una implementación distribuida basada en combinaciones hash de combinaciones SQL. El operador de combinación de difusión push lee filas del lado de entrada para crear un lote de datos. A continuación, ese lote se difunde a todos los servidores que contienen datos del lado del mapa. En los servidores de destino donde se recibe el lote de datos, se crea una combinación hash usando el lote como datos del lado de compilación y, a continuación, se analizan los datos locales como lado de sondeo de la combinación hash.
El optimizador no selecciona automáticamente Push broadcast hash join. Para usar este operador, define el método de unión como PUSH_BROADCAST_HASH_JOIN
en la sugerencia de consulta, como se muestra en el siguiente ejemplo:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=push_broadcast_hash_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
Estos son los resultados:
AlbumTitle | SongName |
---|---|
Verde | La segunda vez |
Verde | Empezar de nuevo |
Verde | Nothing Is The Same |
Verde | Volvamos a estar juntos |
Verde | I Knew You Were Magic |
Verde | Azul |
Verde | 42 |
Aterrorizado | Fight Story |
Nothing To Do With Me | No se trata de la guitarra |
Este es el plan de ejecución:
La entrada de la combinación hash de difusión push es el índice AlbumsByAlbumTitle
.
Esa entrada se serializa en un lote de datos. A continuación, ese lote se envía a todas las divisiones locales del índice SongsBySingerAlbumSongNameDesc
, donde se deserializa y se convierte en una tabla hash. A continuación, la tabla hash usa los datos del índice local como una prueba que devuelve las coincidencias resultantes.
Las coincidencias resultantes también se pueden filtrar por una condición residual antes de devolverse. (Un ejemplo de dónde aparecen las condiciones residuales es en las combinaciones de no igualdad).
Outer apply
Un operador outer apply es similar a un operador cross apply, salvo que un operador outer apply asegura que cada ejecución en el mapa devuelve una fila como mínimo (e incluso produce una fila vacía, si fuera necesario). (Es decir, proporciona semántica de combinación externa izquierda).
Unión recursiva
Un operador de unión recursiva realiza una unión de dos entradas, una que representa un caso base
y otra que representa un caso recursive
. Se usa en consultas de gráficos con barridos de rutas cuantificados. La entrada base se procesa primero y solo una vez. La entrada recursiva se procesa hasta que finaliza la recursión. La recursión finaliza cuando se alcanza el límite superior, si se ha especificado, o cuando la recursión no produce ningún resultado nuevo. En el siguiente ejemplo, se añade la tabla Collaborations
al esquema y se crea un gráfico de propiedades llamado MusicGraph
.
CREATE TABLE Collaborations (
SingerId INT64 NOT NULL,
FeaturingSingerId INT64 NOT NULL,
AlbumTitle STRING(MAX) NOT NULL,
) PRIMARY KEY(SingerId, FeaturingSingerId, AlbumTitle);
CREATE OR REPLACE PROPERTY GRAPH MusicGraph
NODE TABLES(
Singers
KEY(SingerId)
LABEL Singers PROPERTIES(
BirthDate,
FirstName,
LastName,
SingerId,
SingerInfo)
)
EDGE TABLES(
Collaborations AS CollabWith
KEY(SingerId, FeaturingSingerId, AlbumTitle)
SOURCE KEY(SingerId) REFERENCES Singers(SingerId)
DESTINATION KEY(FeaturingSingerId) REFERENCES Singers(SingerId)
LABEL CollabWith PROPERTIES(
AlbumTitle,
FeaturingSingerId,
SingerId),
);
La siguiente consulta de gráfico busca cantantes que hayan colaborado con un cantante determinado o con esos colaboradores.
GRAPH MusicGraph
MATCH (singer:Singers {singerId:42})-[c:CollabWith]->{1,2}(featured:Singers)
RETURN singer.SingerId AS singer, featured.SingerId AS featured
El operador UNION RECURSIVA filtra la tabla Singers
para buscar el cantante con el SingerId
especificado. Esta es la entrada base de la unión recursiva. La entrada recursiva de la unión recursiva incluye un cross apply distribuido u otro operador de combinación para otras consultas que combina repetidamente la tabla Collaborations
con los resultados de la iteración anterior de la combinación. Las filas del formulario de entrada base forman la iteración cero. En cada iteración, la salida se almacena mediante el análisis de cola recursivo. Las filas del análisis de carrete recursivo se combinan con la tabla Collaborations
en spoolscan.featuredSingerId =
Collaborations.SingerId
. La recursión finaliza cuando se completan dos iteraciones, ya que ese es el límite superior especificado en la consulta.
Operadores n-arios
Un operador N-ario es un operador que tiene más de dos elementos secundarios relacionales. Los siguientes operadores son operadores N-arios:
Unión de todo
Un operador UNION ALL combina todos los conjuntos de filas de sus elementos secundarios sin eliminar los duplicados. Los operadores UNION ALL reciben su entrada de operadores UNION INPUT que se distribuyen en varios servidores. El operador UNION ALL requiere que sus entradas tengan el mismo esquema, es decir, el mismo conjunto de tipos de datos para cada columna.
Por ejemplo, con esta consulta:
SELECT 1 a,
2 b
UNION ALL
SELECT 3 a,
4 b
UNION ALL
SELECT 5 a,
6 b;
El tipo de fila de los elementos secundarios consta de dos números enteros.
Estos son los resultados:
a | b |
---|---|
1 | 2 |
3 | 4 |
5 | 6 |
Este es el plan de ejecución:
El operador UNION ALL combina sus filas de entrada y, en este ejemplo, envía los resultados a un operador serialize result.
Una consulta como la siguiente se completaría correctamente porque se usa el mismo conjunto de tipos de datos para cada columna, aunque los elementos secundarios usen variables diferentes para los nombres de las columnas:
SELECT 1 a,
2 b
UNION ALL
SELECT 3 c,
4 e;
Una consulta como la siguiente no se completaría porque los elementos secundarios usan tipos de datos diferentes para las columnas:
SELECT 1 a,
2 b
UNION ALL
SELECT 3 a,
'This is a string' b;
Subconsultas escalares
Una subconsulta escalar es una subexpresión SQL que forma parte de una expresión escalar. Spanner intenta retirar las subconsultas escalares siempre que es posible. Sin embargo, en algunos casos, los planes pueden contener subconsultas escalares de forma explícita.
Por ejemplo, con esta consulta:
SELECT firstname,
IF(firstname = 'Alice', (SELECT Count(*)
FROM songs
WHERE duration > 300), 0)
FROM singers;
Esta es la subexpresión SQL:
SELECT Count(*)
FROM songs
WHERE duration > 300;
Estos son los resultados (de la consulta completa):
FirstName (Nombre) | |
---|---|
Alice | 1 |
Catalina | 0 |
David | 0 |
Lea | 0 |
Marc | 0 |
Este es el plan de ejecución:
El plan de ejecución contiene una subconsulta escalar, que se muestra como Subconsulta escalar, sobre un operador agregado.
A veces, Spanner convierte las subconsultas escalares en otro operador, como una unión o una aplicación cruzada, para mejorar el rendimiento.
Por ejemplo, con esta consulta:
SELECT *
FROM songs
WHERE duration = (SELECT Max(duration)
FROM songs);
Esta es la subexpresión SQL:
SELECT MAX(Duration)
FROM Songs;
Estos son los resultados (de la consulta completa):
SingerId | AlbumId | TrackId | SongName | Duración | SongGenre |
---|---|---|---|---|---|
2 | 1 | 6 | Nothing Is The Same | 303 | BLUES |
Este es el plan de ejecución:
El plan de ejecución no contiene una subconsulta escalar porque Spanner ha convertido la subconsulta escalar en una aplicación cruzada.
Subconsultas de matriz
Una subconsulta de matriz es similar a una subconsulta escalar, pero la subconsulta puede usar más de una fila de entrada. Las filas que se utilizan se convierten en una matriz de salida escalar única que contiene un elemento por cada fila de entrada empleada.
Por ejemplo, con esta consulta:
SELECT a.albumid,
array
(
select concertdate
FROM concerts
WHERE concerts.singerid = a.singerid)
FROM albums AS a;
Esta es la subconsulta:
SELECT concertdate
FROM concerts
WHERE concerts.singerid = a.singerid;
Los resultados de la subconsulta de cada AlbumId
se convierten en una matriz de filas ConcertDate
con respecto a ese AlbumId
. El plan de ejecución contiene una subconsulta de matriz, que se muestra como Subconsulta de matriz, encima de un operador de unión distribuida:
Operadores distribuidos
Los operadores descritos anteriormente en esta página se ejecutan dentro de los límites de una sola máquina. Los operadores distribuidos se ejecutan en varios servidores.
Los siguientes operadores son operadores distribuidos:
- Unión distribuida
- Unión de combinación distribuida
- Aplicación cruzada distribuida
- Aplicación externa distribuida
- Aplicar mutaciones
El operador de unión distribuida es el operador primitivo del que se derivan las aplicaciones cruzadas distribuidas y las aplicaciones externas distribuidas.
Los operadores distribuidos aparecen en los planes de ejecución con una variante de unión distribuida encima de una o varias variantes de unión distribuida local. Una variante de unión distribuida realiza la distribución remota de los subplanes. Una variante de unión distribuida local se encuentra en la parte superior de cada uno de los análisis realizados para la consulta, tal como se muestra en este plan de ejecución:
Las variantes de unión distribuida local aseguran una ejecución de consultas estable cuando se producen reinicios en los límites de división que cambian de forma dinámica.
Siempre que sea posible, una variante de unión distribuida tiene un predicado dividido que da como resultado una poda dividida, lo que significa que los servidores remotos ejecutan subplanes solo en las divisiones que cumplen el predicado. De esta forma, se mejora tanto la latencia como el rendimiento general de las consultas.
Unión distribuida
Un operador de unión distribuida divide conceptualmente una o varias tablas en varias divisiones, evalúa de forma remota una subconsulta de forma independiente en cada división y, a continuación, une todos los resultados.
Por ejemplo, con esta consulta:
SELECT s.songname,
s.songgenre
FROM songs AS s
WHERE s.singerid = 2
AND s.songgenre = 'ROCK';
Estos son los resultados:
SongName | SongGenre |
---|---|
Empezar de nuevo | ROCK |
La segunda vez | ROCK |
Fight Story | ROCK |
Este es el plan de ejecución:
El operador UNION distribuido envía subplanes a servidores remotos, que realizan un examen de la tabla en las divisiones que cumplen el predicado WHERE
s.SingerId = 2 AND s.SongGenre = 'ROCK'
de la consulta. Un operador serialize
result calcula los valores SongName
y SongGenre
de las filas devueltas por los análisis de tabla. El operador UNION distribuido devuelve los resultados combinados de los servidores remotos como resultados de la consulta SQL.
Unión de combinación distribuida
El operador unión de combinación distribuida distribuye una consulta entre varios servidores remotos. Después, combina los resultados de la consulta para generar un resultado ordenado, lo que se conoce como ordenación por fusión distribuida.
Una unión de combinación distribuida ejecuta los siguientes pasos:
El servidor raíz envía una subconsulta a cada servidor remoto que aloja una división de los datos consultados. La subconsulta incluye instrucciones para que los resultados se ordenen de una forma específica.
Cada servidor remoto ejecuta la subconsulta en su división y, a continuación, envía los resultados en el orden solicitado.
El servidor raíz combina la subconsulta ordenada para generar un resultado completamente ordenado.
La unión de combinación distribuida está activada de forma predeterminada en la versión 3 de Spanner y versiones posteriores.
Aplicación cruzada distribuida
Un operador aplicación cruzada distribuida (DCA) amplía el operador aplicación cruzada ejecutándose en varios servidores. Los grupos de entrada de DCA lotes de filas (a diferencia de un operador CROSS APPLY normal, que actúa en una sola fila de entrada a la vez). El lado del mapa de DCA es un conjunto de operadores CROSS APPLY que se ejecutan en servidores remotos.
Por ejemplo, con esta consulta:
SELECT albumtitle
FROM songs
JOIN albums
ON albums.albumid = songs.albumid;
Los resultados tienen el siguiente formato:
AlbumTitle |
---|
Verde |
Nothing To Do With Me |
Reproducir |
Total Junk |
Verde |
Este es el plan de ejecución:
La entrada de DCA contiene un análisis de índice en el índice SongsBySingerAlbumSongNameDesc
que agrupa filas de AlbumId
. El lado de mapa de este operador de aplicación cruzada es un análisis de índice en el índice AlbumsByAlbumTitle
, sujeto al predicado de AlbumId
en la fila de entrada que coincida con la clave AlbumId
en el índice AlbumsByAlbumTitle
. La asignación devuelve el SongName
de los valores de SingerId
en las filas de entrada por lotes.
Para resumir el proceso de DCA en este ejemplo, la entrada del DCA son las filas agrupadas de la tabla Albums
y la salida del DCA es la aplicación de estas filas al mapa del análisis de índice.
Aplicación externa distribuida
Un operador OUTER APPLY distribuido amplía el operador OUTER APPLY ejecutándose en varios servidores, de forma similar a como un operador CROSS APPLY distribuido amplía un operador CROSS APPLY.
Por ejemplo, con esta consulta:
SELECT lastname,
concertdate
FROM singers LEFT OUTER join@{JOIN_TYPE=APPLY_JOIN} concerts
ON singers.singerid=concerts.singerid;
Los resultados tienen el siguiente formato:
LastName | ConcertDate |
---|---|
Trentor | 2014-02-18 |
Smith | 2011-09-03 |
Smith | 2010-06-06 |
Lomond | 2005-04-30 |
Martin | 2015-11-04 |
Richards |
Este es el plan de ejecución:
Aplicar mutaciones
Un operador apply mutations aplica las mutaciones de una declaración de manipulación de datos (DML) a la tabla. Es el operador superior de un plan de consulta de una instrucción DML.
Por ejemplo, con esta consulta:
DELETE FROM singers
WHERE firstname = 'Alice';
Estos son los resultados:
4 rows deleted This statement deleted 4 rows and did not return any rows.
Este es el plan de ejecución:
Información adicional
En esta sección se describen los elementos que no son operadores independientes, sino que ejecutan tareas para admitir uno o varios de los operadores que se han indicado anteriormente. Los elementos que se describen aquí son técnicamente operadores, pero no son operadores independientes en tu plan de consulta.
Constructor de struct
Un constructor de struct crea un struct, o una colección de campos. Normalmente, crea una struct para las filas que resultan de una operación de cálculo. Un constructor de struct no es un operador independiente. En su lugar, aparece en los operadores compute struct u serialize result.
En el caso de una operación de estructura de cálculo, el constructor de la estructura crea una estructura para que las columnas de las filas calculadas puedan usar una sola referencia de variable a la estructura.
En el caso de una operación de serialización de resultados, el constructor de struct crea un struct para serializar los resultados.
Por ejemplo, con esta consulta:
SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;
Estos son los resultados:
A |
---|
1 |
Este es el plan de ejecución:
En el plan de ejecución, los constructores de struct aparecen dentro de un operador de resultado de serialización.