Agregue un hint MAPJOIN a una instrucción SELECT para forzar que la unión se ejecute en la etapa map. De esta manera se omiten las etapas shuffle y reduce. Esto reduce la sobrecarga de transmisión de datos y mejora el rendimiento de las consultas cuando se une una tabla grande con una o más tablas pequeñas. Utilice MAPJOIN cuando el optimizador no aplique automáticamente la unión en la etapa map a su consulta.
Cómo funciona
Una operación JOIN estándar en MaxCompute pasa por tres etapas: map, shuffle y reduce. La lógica de unión se ejecuta en la etapa reduce, lo cual requiere redistribuir los datos entre los nodos.
MAPJOIN cambia este comportamiento: carga todo el contenido de la tabla pequeña especificada en memoria durante la etapa map. Después, cada mapper ejecuta la unión de forma local con los datos en memoria. Así se eliminan por completo las etapas shuffle y reduce.
El hint indica el nombre de la tabla pequeña que se cargará en memoria. Para cada mapper que lee filas de la tabla grande, la tabla pequeña se lee por completo desde la memoria:
SELECT /*+ mapjoin(a) */ a.shop_name, a.total_price, b.total_price
FROM sale_detail_sj a JOIN sale_detail b
ON a.total_price < b.total_price OR a.total_price + b.total_price < 500;
En este ejemplo, a (con alias sale_detail_sj) es la tabla pequeña. El hint especifica a, por lo que a es lo que se carga en memoria en cada mapper.
Límites
Memoria y cantidad de tablas
|
Restricción |
Límite |
Notas |
|
Memoria total para todas las tablas pequeñas |
512 MB |
Se mide después de cargar y descomprimir los datos en memoria, no según el tamaño comprimido almacenado en MaxCompute |
|
Número máximo de tablas pequeñas |
128 |
Si especifica más de 128, se devuelve un error de sintaxis |
Tipos de JOIN compatibles
|
Tipo de JOIN |
Compatible |
Requisito |
|
INNER JOIN |
Sí |
La tabla grande puede ser la izquierda o la derecha |
|
LEFT OUTER JOIN |
Sí |
La tabla izquierda debe ser la tabla grande |
|
RIGHT OUTER JOIN |
Sí |
La tabla derecha debe ser la tabla grande |
|
FULL OUTER JOIN |
No |
— |
Notas de uso
Agregue /*+ mapjoin(<table_name>) */ inmediatamente después de SELECT. Tenga en cuenta lo siguiente:
Haga referencia a los alias, no a los nombres originales de las tablas. Cuando la tabla pequeña o la subconsulta tiene un alias, utilice ese alias dentro del hint.
Las subconsultas son compatibles como tablas pequeñas. Use una subconsulta en lugar de una referencia de tabla y haga referencia a su alias en el hint.
Separe varias tablas pequeñas con comas:
/*+ mapjoin(a,b,c) */Se admiten uniones sin igualdad (non-equi joins) y condiciones OR. El SQL estándar de MaxCompute no permite uniones sin igualdad ni lógica OR en la condición ON, pero MAPJOIN sí.
Los productos cartesianos son compatibles si usa
ON 1 = 1(por ejemplo,SELECT /*+ mapjoin(a) */ a.id FROM shop a JOIN table_name b ON 1=1). Sin embargo, esto aumenta significativamente el volumen de datos de salida.
Algunos tipos de subconsultas, como SCALAR, IN, NOT IN, EXISTS y NOT EXISTS, se pueden convertir en operaciones JOIN durante la ejecución. Si el resultado de la subconsulta califica como tabla pequeña, agregue un hint MAPJOIN a la instrucción de la subconsulta para aplicar explícitamente el algoritmo de unión en la etapa map.
Datos de ejemplo
Los ejemplos de este tema usan las tablas sale_detail y sale_detail_sj. Ejecute las siguientes instrucciones para crear las tablas e insertar los datos de ejemplo.
-- Create a partitioned table named sale_detail.
CREATE TABLE IF NOT EXISTS sale_detail
(
shop_name STRING,
customer_id STRING,
total_price DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);
CREATE TABLE IF NOT EXISTS sale_detail_sj
(
shop_name STRING,
customer_id STRING,
total_price DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);
-- Add partitions.
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china');
ALTER TABLE sale_detail_sj ADD PARTITION (sale_date='2013', region='china');
-- Insert sample data.
INSERT INTO sale_detail PARTITION (sale_date='2013', region='china')
VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
INSERT INTO sale_detail_sj PARTITION (sale_date='2013', region='china')
VALUES ('s1','c1',100.1),('s2','c2',100.2),('s5','c2',100.2),('s2','c2',100.2);
Ejemplo
Una sale_detail_sj (tabla pequeña, con alias a) con sale_detail (tabla grande, con alias b) mediante una condición sin igualdad. Devuelva las filas donde el valor de total_price de a sea menor que el de total_price de b, o bien donde la suma de ambos precios sea menor que 500.
-- Allow a full scan on the partitioned table.
SET odps.sql.allow.fullscan=true;
-- Use MAPJOIN with a non-equi join condition.
SELECT /*+ mapjoin(a) */
a.shop_name,
a.total_price,
b.total_price
FROM sale_detail_sj a JOIN sale_detail b
ON a.total_price < b.total_price OR a.total_price + b.total_price < 500;
La consulta devuelve el siguiente resultado:
+-----------+-------------+--------------+
| shop_name | total_price | total_price2 |
+-----------+-------------+--------------+
| s1 | 100.1 | 100.1 |
| s2 | 100.2 | 100.1 |
| s5 | 100.2 | 100.1 |
| s2 | 100.2 | 100.1 |
| s1 | 100.1 | 100.2 |
| s2 | 100.2 | 100.2 |
| s5 | 100.2 | 100.2 |
| s2 | 100.2 | 100.2 |
| s1 | 100.1 | 100.3 |
| s2 | 100.2 | 100.3 |
| s5 | 100.2 | 100.3 |
| s2 | 100.2 | 100.3 |
+-----------+-------------+--------------+