Todos los productos
Search
Centro de documentos

Realtime Compute for Apache Flink:Sentencias JOIN para tablas de dimensiones

Última actualización: Sep 03, 2026

Cada registro de datos de streaming se puede combinar con un origen de datos externo de tabla de dimensiones. Realtime Compute for Apache Flink utiliza esta capacidad para enriquecer los flujos con datos de dimensión.

Descripción general del JOIN de tabla de dimensiones

Un JOIN de tabla de dimensiones (también conocido como Lookup Join) consulta una tabla de dimensiones externa durante el procesamiento de cada dato del flujo y enriquece el flujo principal con columnas de dimensión. Se usa comúnmente para agregar información de diccionario o de dimensión a los flujos de eventos.

Aspectos clave de un JOIN de tabla de dimensiones:

  • Sintaxis: Utilice FOR SYSTEM_TIME AS OF PROCTIME() para indicar que cada fila del flujo principal consulta los datos actuales de la tabla de dimensiones en tiempo de procesamiento, no una instantánea.

  • Estrategia de caché: Almacene en caché los datos de dimensión en la capa del conector para reducir la carga sobre el sistema externo.

  • Comportamiento de búsqueda: Use un hint LOOKUP para configurar el modo síncrono o asíncrono, la capacidad del búfer, la estrategia de reintentos, entre otros.

  • Estrategia de unión física: Emplee hints como SHUFFLE_HASH para controlar el comportamiento de redistribución (shuffle) y mitigar el sesgo de datos.

  • Configuración a nivel de trabajo: Utilice el comando SET para ajustar parámetros globales de la familia table.exec.*.

Sintaxis del JOIN de tabla de dimensiones

SELECT column-names
FROM table1 [AS <alias1>]
[LEFT] JOIN table2 FOR SYSTEM_TIME AS OF PROCTIME() [AS <alias2>]
ON table1.column-name1 = table2.key-name1;
Nota
  • FOR SYSTEM_TIME AS OF PROCTIME() es obligatorio. Indica al motor que combine cada fila del flujo principal con la instantánea de la tabla de dimensiones correspondiente al tiempo de procesamiento actual.

  • La cláusula ON debe contener una condición de igualdad en una columna que la tabla de dimensiones pueda consultar de forma aleatoria.

  • En la cláusula ON, puede aplicar funciones de conversión de tipos como CAST a las columnas de la tabla origen. Si los tipos de columna de la fuente y la dimensión no coinciden, convierta la columna de origen para que coincida con el tipo de la columna de dimensión.

Límites y consideraciones

  • El JOIN de tabla de dimensiones solo admite combinaciones con la instantánea actual de dicha tabla.

  • Las tablas de dimensiones solo son compatibles con INNER JOIN y LEFT JOIN. No se admiten RIGHT JOIN ni FULL JOIN.

  • Para una unión uno a uno, asegúrese de que la condición de combinación contenga un predicado de igualdad en una columna única dentro de la tabla de dimensiones.

  • Para cada dato de streaming, la unión solo considera la versión más reciente de la tabla de dimensiones en el momento del procesamiento. Una vez realizada la unión, cualquier cambio posterior (inserción, actualización o eliminación) en los datos de dimensión no se propaga a las filas ya combinadas. Para conocer el comportamiento específico de cada conector, consulte la documentación correspondiente de connector.

Estrategias de caché para tablas de dimensiones

La mayoría de los conectores admiten estrategias de caché para los JOIN de tablas de dimensiones. La compatibilidad varía ligeramente entre conectores; consulte la documentación del conector correspondiente para obtener detalles. Las estrategias de caché comunes son:

Estrategia

Comportamiento

None (predeterminado)

Sin almacenamiento en caché.

LRU

Almacena en caché un subconjunto de la tabla de dimensiones. Cada fila del flujo de origen busca primero en la caché; si no encuentra el dato, el motor consulta la tabla de dimensiones física.

ALL

Almacena en caché toda la tabla de dimensiones. Antes de iniciar el trabajo, el motor carga todas las filas en la caché; cada búsqueda posterior se resuelve desde allí, y un fallo de caché significa que la clave no existe. Las opciones específicas del conector controlan las recargas periódicas o programadas de la tabla de dimensiones. Esta estrategia es adecuada para tablas de dimensiones pequeñas que no requieren actualizaciones frecuentes y exigen el máximo rendimiento.

Nota
  • Elija entre frescura de datos y rendimiento según sus requisitos de negocio. Si la frescura es crítica, puede deshabilitar la caché y leer directamente desde la tabla de dimensiones.

  • Cuando la caché está habilitada, combine LRU con un TTL para mantener los datos razonablemente actualizados. El TTL puede establecerse en un valor corto (por ejemplo, de varios segundos a decenas de segundos) para que la caché se actualice periódicamente desde el origen.

  • Al usar la estrategia ALL, supervise cuidadosamente la memoria del nodo para evitar errores OOM.

  • Con la estrategia ALL, el motor carga los datos de dimensión de forma asíncrona, por lo que debe aumentar la memoria del nodo de JOIN de dimensión. Como regla general, increméntela al doble del tamaño de los datos de la tabla de dimensiones remota.

Ajuste de un JOIN de tabla de dimensiones

Categorías de parámetros de ajuste y cómo pasarlos

El ajuste de un JOIN de tabla de dimensiones implica tres categorías de parámetros. Cada categoría tiene su propio mecanismo de transmisión, y usar el mecanismo incorrecto provoca que el hint se ignore silenciosamente.

Categoría

Parámetros típicos

Cómo pasarlos

Alcance

Opciones WITH del conector

lookup.cache, lookup.partial-cache.max-rows, lookup.partial-cache.expire-after-write

Establézcalos en la cláusula WITH (...) al crear la tabla, o anúlelos durante la consulta con /*+ OPTIONS('key'='value') */.

Tabla individual

Opciones del hint LOOKUP

table, async, capacity, timeout, output-mode, retry-predicate, retry-strategy, fixed-delay, max-attempts, shuffle

/*+ LOOKUP('table'='dim', 'async'='true', 'capacity'='100') */

Operación de unión individual

TableConfig a nivel de trabajo de Flink

Configuraciones globales cuyas claves comienzan con table.exec.* o table.optimizer.*

Ejecute SET 'table.exec.async-lookup.buffer-capacity' = '3072'; al inicio del trabajo.

Todo el trabajo

Importante
  • Un hint OPTIONS() solo anula las opciones que el conector acepta en la cláusula WITH. No acepta claves TableConfig table.exec.*; las claves no válidas se ignoran silenciosamente.

  • Un hint LOOKUP() solo reconoce las claves fijas listadas en la tabla anterior. No acepta claves de configuración completas de Flink. Por ejemplo, para ajustar el búfer de búsqueda asíncrona debe escribir 'capacity'='100'; escribir 'table.exec.async-lookup.buffer-capacity'='100' no surte efecto.

  • Para cambiar un parámetro global que no está expuesto mediante ningún hint, use SET 'xxx' = 'yyy';.

Anular opciones del conector con el hint OPTIONS

Un hint OPTIONS() le permite anular las opciones WITH de una tabla directamente en una consulta, sin modificar la sentencia CREATE TABLE. Se usa comúnmente para ajustar el comportamiento de la caché.

SELECT t.id, t.name, w.phoneNumber
FROM kafka_input AS t
LEFT JOIN phoneNumber /*+ OPTIONS(
  'lookup.cache' = 'PARTIAL',
  'lookup.partial-cache.max-rows' = '1000'
) */ FOR SYSTEM_TIME AS OF PROCTIME() AS w
ON t.name = w.name;

Cada clave dentro de OPTIONS debe ser una opción WITH que el conector realmente admita.

Nota

Las opciones lookup.cache y lookup.partial-cache.max-rows mostradas arriba pertenecen a la interfaz genérica LookupCache de Flink (FLIP-221), y solo aplican a conectores más recientes que implementan esta interfaz (como Fluss y JDBC). Las estrategias None/LRU/ALL descritas en la sección "Estrategias de caché para tablas de dimensiones" corresponden a conectores heredados, los cuales exponen su comportamiento de caché mediante diferentes opciones WITH. Consulte la documentación del connector de destino para confirmar qué opciones y estrategias de caché admite, y evite usar parámetros que el conector no reconozca.

Configurar el comportamiento de búsqueda con el hint LOOKUP

El hint LOOKUP se comporta de manera consistente con la versión de la comunidad de Apache Flink. Configura el modo síncrono/asíncrono, los reintentos y el comportamiento de redistribución (shuffle) para una operación de unión individual. Para más detalles, consulte Apache Flink Lookup Hint.

  • El hint LOOKUP está disponible solo en VVR 8.0 y versiones posteriores.

  • La opción 'shuffle' = 'true' está disponible solo en VVR 8.0.8 y versiones posteriores.

  • Los alias son compatibles en VVR 8.0 y versiones posteriores. Cuando la tabla de dimensiones se referencia mediante un alias, el hint debe usar ese alias.

Opciones compatibles

Opción

Significado

Valor

table

Nombre o alias de la tabla de dimensiones a la que aplica el hint.

Cadena de nombre de tabla o alias.

async

Indica si se habilita la búsqueda asíncrona.

true / false

output-mode

Orden de salida de las búsquedas asíncronas.

ordered / allow_unordered

capacity

Capacidad de la cola de búfer para búsquedas asíncronas.

Entero.

timeout

Tiempo de espera para una búsqueda asíncrona.

Duración (por ejemplo, 180s).

retry-predicate

Condición que desencadena un reintento.

Actualmente solo se admite lookup_miss.

retry-strategy

Estrategia de reintento.

Actualmente solo se admite fixed_delay.

fixed-delay

Intervalo fijo entre reintentos.

Duración (por ejemplo, 10s).

max-attempts

Número máximo de intentos de reintento.

Entero.

shuffle

Indica si se realiza una redistribución antes de la unión con la tabla de dimensiones.

true / false

Comportamiento de la opción shuffle

La opción shuffle afecta la estrategia de redistribución de la unión de tabla de dimensiones. El comportamiento efectivo en cada escenario es el siguiente.

Escenario

Estrategia de unión

No se establece 'shuffle' = 'true'.

Se utiliza la estrategia de redistribución predeterminada del motor.

No se establece 'shuffle' = 'true' y el conector de dimensiones no proporciona una estrategia de unión personalizada.

Se utiliza la estrategia de redistribución predeterminada del motor.

Se establece 'shuffle' = 'true' y el conector de dimensiones no proporciona una estrategia de unión personalizada.

Se usa SHUFFLE_HASH de forma predeterminada. Para más detalles, consulte la sección SHUFFLE_HASH a continuación.

Se establece 'shuffle' = 'true' y el conector de dimensiones proporciona una estrategia de unión personalizada.

Se utiliza la estrategia de redistribución personalizada proporcionada por el conector.

Nota

Actualmente, solo el conector Streaming Lakehouse Paimon proporciona una estrategia de redistribución personalizada. Cuando las columnas de unión cubren todas las columnas de bucket, la redistribución se basa en el bucket.

Ejemplos de código
-- Apply the shuffle strategy only to dimension table dim1.
SELECT /*+ LOOKUP('table'='dim1', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() ON T.a = dim1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() ON T.b = dim2.b;

-- Apply the shuffle strategy to both dim1 and dim2.
SELECT /*+ LOOKUP('table'='dim1', 'shuffle' = 'true'), LOOKUP('table'='dim2', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() ON T.a = dim1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() ON T.b = dim2.b;

-- When dim1 is referenced by the alias D1, the hint must use the alias.
SELECT /*+ LOOKUP('table'='D1', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() AS D1 ON T.a = D1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() AS D2 ON T.b = D2.b;

-- Apply the shuffle strategy to both dim1 and dim2 using their aliases.
SELECT /*+ LOOKUP('table'='D1', 'shuffle' = 'true'), LOOKUP('table'='D2', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() AS D1 ON T.a = D1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() AS D2 ON T.b = D2.b;

Establecer TableConfig a nivel de trabajo con SET

Las claves table.exec.* y similares de TableConfig son configuraciones globales a nivel de trabajo. Deben pasarse mediante SET; ni el hint LOOKUP ni el hint OPTIONS las aceptan.

Claves comunes de TableConfig para JOIN de tabla de dimensiones:

Clave

Significado

Predeterminado

table.exec.async-lookup.buffer-capacity

Capacidad de la cola de búfer para búsquedas asíncronas (valor predeterminado a nivel de trabajo).

100

table.exec.async-lookup.timeout

Tiempo de espera para búsquedas asíncronas (valor predeterminado a nivel de trabajo).

3 min

table.exec.async-lookup.output-mode

Orden de salida de las búsquedas asíncronas (valor predeterminado a nivel de trabajo).

ordered

-- Set job-level defaults at the beginning of the job.
SET 'table.exec.async-lookup.buffer-capacity' = '3072';
SET 'table.exec.async-lookup.timeout' = '180s';

INSERT INTO sink_table
SELECT ...
FROM src_table
LEFT JOIN dim_table FOR SYSTEM_TIME AS OF PROCTIME() AS d
ON src_table.key = d.key;
Nota

Cuando SET y un hint LOOKUP establecen el mismo parámetro, el hint LOOKUP en la unión individual tiene prioridad.

Controlar la redistribución con hints de estrategia de unión

Los hints de estrategia de unión controlan el comportamiento de redistribución para las uniones de tablas de dimensiones. Los hints disponibles son SHUFFLE_HASH, REPLICATED_SHUFFLE_HASH y SKEW. La siguiente tabla muestra qué estrategia de unión se ajusta a cada estrategia de caché.

Estrategia de caché

SHUFFLE_HASH

REPLICATED_SHUFFLE_HASH (equivalente a SKEW)

None

No se recomienda esta estrategia; el flujo principal incurre en sobrecarga de red adicional.

No se recomienda esta estrategia; el flujo principal incurre en sobrecarga de red adicional.

LRU

Considere esta estrategia cuando la E/S de búsqueda de dimensiones sea el cuello de botella. Si el flujo principal presenta localidad temporal en la clave de unión, mejora la tasa de aciertos de caché, reduce las solicitudes de E/S y aumenta el rendimiento general.

Importante

El flujo principal incurre en sobrecarga de red adicional. Si el flujo principal tiene sesgo en la clave de unión y encuentra un cuello de botella de rendimiento, considere usar REPLICATED_SHUFFLE_HASH en su lugar.

Considere esta estrategia cuando la E/S de búsqueda de dimensiones sea el cuello de botella y el flujo principal tenga sesgo en la clave de unión. Si el flujo principal presenta localidad temporal en la clave de unión, mejora la tasa de aciertos de caché, reduce las solicitudes de E/S y aumenta el rendimiento general.

ALL

Recomendada cuando la memoria de la tabla de dimensiones se convierte en el cuello de botella. El uso de memoria puede reducirse a 1 / paralelismo.

Importante

El flujo principal incurre en sobrecarga de red adicional. Si el flujo principal tiene sesgo en la clave de unión y encuentra un cuello de botella de rendimiento, considere usar REPLICATED_SHUFFLE_HASH en su lugar.

Recomendada cuando la memoria de la tabla de dimensiones se convierte en el cuello de botella y el flujo principal tiene sesgo en la clave de unión. El uso de memoria se reduce a cantidad de buckets / paralelismo.

Importante
  • La opción shuffle del hint LOOKUP ya cubre lo que hace SHUFFLE_HASH. Cuando ambos están presentes, prevalece la opción shuffle del hint LOOKUP.

  • La opción shuffle del hint LOOKUP aún no maneja el sesgo de datos. Cuando se combina con REPLICATED_SHUFFLE_HASH o SKEW, la estrategia especificada por REPLICATED_SHUFFLE_HASH o SKEW tiene prioridad.

SHUFFLE_HASH

Efecto: Usar una estrategia shuffle-hash en un JOIN de tabla de dimensiones redistribuye el flujo principal por clave de unión antes de la unión. Combinada con la estrategia de caché LRU, aumenta la tasa de aciertos de caché y reduce las solicitudes de E/S; combinada con la estrategia de caché ALL, reduce el uso de memoria. Un solo hint SHUFFLE_HASH puede especificar varias tablas de dimensiones.

Límites: SHUFFLE_HASH reduce el uso de memoria, pero los datos ascendentes deben redistribuirse por clave de unión, lo que introduce sobrecarga de red adicional. Evítelo en los siguientes dos casos:

  • El flujo principal tiene un sesgo significativo en la clave de unión. Usar SHUFFLE_HASH convertiría el nodo de unión en un cuello de botella, causando contrapresión severa en trabajos de streaming o colas largas en trabajos por lotes. Use REPLICATED_SHUFFLE_HASH en su lugar.

  • La tabla de dimensiones es pequeña y la estrategia de caché ALL no presenta cuellos de botella de memoria. En este caso, la memoria ahorrada por SHUFFLE_HASH no justifica la sobrecarga de red adicional.

Ejemplo de código:

-- Enable SHUFFLE_HASH for dim1 only.
SELECT /*+ SHUFFLE_HASH(dim1) */ ...

-- Enable SHUFFLE_HASH for both dim1 and dim2.
SELECT /*+ SHUFFLE_HASH(dim1, dim2) */ ...

-- When dim1 is referenced by the alias D1, the hint must use the alias.
SELECT /*+ SHUFFLE_HASH(D1) */ ...

REPLICATED_SHUFFLE_HASH

Efecto: REPLICATED_SHUFFLE_HASH se comporta esencialmente igual que SHUFFLE_HASH, excepto que distribuye aleatoriamente las filas del flujo principal con la misma clave entre N instancias paralelas. Esto aborda el cuello de botella de rendimiento causado por el sesgo de datos. Un solo hint REPLICATED_SHUFFLE_HASH puede especificar varias tablas de dimensiones.

Límites:

  • Configure la cantidad de buckets para datos sesgados con table.exec.skew-join.replicate-num (predeterminado: 16). Su valor no puede exceder el paralelismo del nodo de unión de dimensiones. Para más detalles, consulte Ajuste SQL a nivel de trabajo.

  • No se admiten flujos de actualización. Usar este hint cuando el flujo principal es un flujo de actualización genera un error.

Ejemplo de código:

SELECT /*+ REPLICATED_SHUFFLE_HASH(dim1) */ ...

SKEW

Efecto: Cuando se sabe que la tabla especificada tiene sesgo, el optimizador aplica la estrategia replicated-shuffle-hash. SKEW es azúcar sintáctica; internamente se implementa con redistributed shuffle hash.

Límites:

  • Cada hint SKEW solo puede especificar una tabla.

  • El nombre de la tabla debe referirse a la tabla principal que tiene el sesgo, no a la tabla de dimensiones.

  • No se admiten flujos de actualización. Usar este hint cuando el flujo principal es un flujo de actualización genera un error.

Ejemplo de código:

SELECT /*+ SKEW(src) */  ...

Ejemplos

Ejemplo 1: Un JOIN básico de tabla de dimensiones

La forma más básica: enriquecer un flujo de Kafka con una tabla de dimensiones de MySQL. No se utilizan hints de ajuste.

CREATE TEMPORARY TABLE kafka_input (
  id   BIGINT,
  name VARCHAR,
  age  BIGINT
) WITH (
  'connector' = 'kafka',
  'topic' = '<yourTopic>',
  'properties.bootstrap.servers' = '<yourKafkaBrokers>',
  'properties.group.id' = '<yourKafkaConsumerGroupId>',
  'format' = 'csv'
);

CREATE TEMPORARY TABLE phoneNumber (
  name        VARCHAR,
  phoneNumber BIGINT,
  PRIMARY KEY (name) NOT ENFORCED
) WITH (
  'connector' = 'mysql',
  'hostname' = '<yourHostname>',
  'port' = '3306',
  'username' = '<yourUsername>',
  'password' = '<yourPassword>',
  'database-name' = '<yourDatabaseName>',
  'table-name' = '<yourTableName>'
);

CREATE TEMPORARY TABLE result_infor (
  id          BIGINT,
  phoneNumber BIGINT,
  name        VARCHAR
) WITH (
  'connector' = 'blackhole'
);

INSERT INTO result_infor
SELECT
  t.id,
  w.phoneNumber,
  t.name
FROM kafka_input AS t
JOIN phoneNumber FOR SYSTEM_TIME AS OF PROCTIME() AS w
ON t.name = w.name;

Ejemplo 2: Habilitar caché con el hint OPTIONS y configurar búsqueda asíncrona con el hint LOOKUP

Escenario de ajuste: el QPS de la tabla de dimensiones es insuficiente. Desea activar la caché parcial en la tabla de dimensiones y habilitar la búsqueda asíncrona con una cola de búfer más grande.

INSERT INTO user_behavior_wide
SELECT /*+ LOOKUP('table' = 't2', 'async' = 'true', 'capacity' = '3072') */
  t1.member_id AS member_id,
  t2.tag AS tag
FROM user_behavior_datagen AS t1
LEFT JOIN fluss.fluss.user_active_info /*+ OPTIONS(
    'lookup.cache' = 'PARTIAL',
    'lookup.partial-cache.max-rows' = '1000'
  ) */
FOR SYSTEM_TIME AS OF PROCTIME() AS t2
ON t1.member_id = t2.member_id;
  • Las opciones del conector (lookup.cache, lookup.partial-cache.max-rows) se pasan mediante un hint OPTIONS() colocado justo después de la referencia a la tabla de dimensiones; esto anula las opciones WITH correspondientes en tiempo de consulta.

  • El comportamiento de búsqueda (async, capacity) se configura mediante un hint LOOKUP() colocado después de SELECT. OPTIONS y LOOKUP son dos tipos de hints diferentes y deben escribirse por separado; combinarlos desactiva silenciosamente el hint.

Ejemplo 3: Ajustar el búfer de búsqueda asíncrona a nivel de trabajo con SET

Escenario de ajuste: varios JOIN de tablas de dimensiones en el mismo trabajo necesitan un búfer de búsqueda asíncrona más grande. Desea que el cambio se aplique globalmente y habilitar el modo asíncrono mediante el hint LOOKUP.

SET 'table.exec.async-lookup.buffer-capacity' = '3072';
SET 'table.exec.async-lookup.timeout' = '180s';

INSERT INTO user_behavior_wide
SELECT /*+ LOOKUP('table' = 't2', 'async' = 'true') */
  t1.member_id,
  t2.tag
FROM user_behavior_datagen AS t1
LEFT JOIN fluss.fluss.user_active_info
FOR SYSTEM_TIME AS OF PROCTIME() AS t2
ON t1.member_id = t2.member_id;
  • table.exec.async-lookup.buffer-capacity y parámetros similares son claves TableConfig a nivel de trabajo y solo pueden establecerse con SET. Incluirlos dentro de OPTIONS o LOOKUP no surte efecto.

  • Cuando el hint LOOKUP no especifica capacity, se utiliza el valor global de SET. Si ambos se especifican, el hint LOOKUP tiene prioridad en esa unión individual.