Todos os produtos
Search
Central de documentação

Realtime Compute for Apache Flink:Instruções JOIN para tabelas de dimensão

Última atualização: Jun 27, 2026

Una cada fluxo de dados de streaming a uma fonte de dados externa de tabela de dimensão. O Realtime Compute for Apache Flink usa esse recurso para enriquecer fluxos com dados dimensionais.

Visão geral do JOIN de tabela de dimensão

Um JOIN de tabela de dimensão (também chamado de Lookup Join) consulta uma tabela de dimensão externa durante o processamento de cada dado do fluxo e enriquece o fluxo principal com colunas de dimensão. Esse recurso é comum para adicionar informações de dicionário ou dimensão a fluxos de eventos.

Principais aspectos de um JOIN de tabela de dimensão:

  • Sintaxe: Use FOR SYSTEM_TIME AS OF PROCTIME() para indicar que cada linha do fluxo principal consulta os dados atuais da tabela de dimensão no momento do processamento, e não um snapshot.

  • Estratégia de cache: Armazene dados de dimensão em cache na camada do conector para reduzir a carga no sistema externo.

  • Comportamento de lookup: Use um hint LOOKUP para configure modo síncrono/assíncrono, capacidade de buffer, estratégia de nova tentativa, entre outros parâmetros.

  • Estratégia física de junção: Aplique hints como SHUFFLE_HASH para controlar o comportamento de shuffle e mitigar a distorção de dados.

  • Configuração no nível do job: execute o comando SET para ajustar parâmetros globais da família table.exec.*.

Sintaxe do JOIN de tabela de dimensão

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
  • A cláusula FOR SYSTEM_TIME AS OF PROCTIME() é obrigatória. Ela instrui o mecanismo a unir cada linha do fluxo principal ao snapshot da tabela de dimensão correspondente ao tempo de processamento atual.

  • A cláusula ON deve conter uma condição de igualdade em uma coluna que permita consultas aleatórias na tabela de dimensão.

  • Na cláusula ON, aplique funções de conversão de tipo, como CAST, às colunas da tabela de origem. Se os tipos das colunas de origem e de dimensão não coincidirem, converta a coluna de origem para alinhar com o tipo da coluna de dimensão.

Limites e considerações

  • O JOIN de tabela de dimensão suporta apenas junções com o snapshot atual da tabela de dimensão.

  • Tabelas de dimensão aceitam somente INNER JOIN e LEFT JOIN. RIGHT JOIN e FULL JOIN não são suportados.

  • Para junções um-para-um, garanta que a condição de junção contenha um predicado de igualdade em uma coluna exclusiva na tabela de dimensão.

  • Para cada dado de streaming, a junção considera apenas a versão mais recente da tabela de dimensão no momento do processamento. Após a execução da junção, alterações subsequentes (inserção, atualização ou exclusão) nos dados de dimensão não se propagam para as linhas já unidas. Para detalhes sobre o comportamento específico de cada conector, consulte a documentação do conector correspondente.

Estratégias de cache para tabelas de dimensão

A maioria dos conectores oferece suporte a estratégias de cache para JOINs de tabelas de dimensão. O nível de suporte varia ligeiramente entre conectores — consulte a documentação do conector específico para obter detalhes. As estratégias de cache mais comuns são:

Estratégia

Comportamento

None (padrão)

Sem armazenamento em cache.

LRU

Armazena em cache um subconjunto da tabela de dimensão. Cada linha do fluxo de origem consulta primeiro o cache; em caso de falha (miss), o mecanismo consulta a tabela de dimensão física.

ALL

Armazena toda a tabela de dimensão em cache. Antes do início do job, o mecanismo carrega todas as linhas para o cache; todas as consultas subsequentes são atendidas pelo cache, e uma falha indica que a chave não existe. Opções específicas do conector controlam recargas periódicas ou agendadas da tabela de dimensão. Esta estratégia é ideal para tabelas de dimensão pequenas, que não exigem atualizações frequentes e demandam throughput máximo.

Nota
  • Escolha entre atualidade e desempenho com base nos requisitos do seu negócio. Se a atualidade dos dados for crítica, desative o cache e leia diretamente da tabela de dimensão.

  • Ao ative o cache, combine LRU com um TTL para manter os dados em cache razoavelmente atualizados. defina o TTL com um valor curto — por exemplo, de alguns segundos a dezenas de segundos — para que o cache seja atualizado periodicamente a partir da origem.

  • Ao utilizar a estratégia ALL, monitore atentamente a memória do nó para evitar erros de OOM (Out Of Memory).

  • Na estratégia ALL, o mecanismo carrega os dados de dimensão de forma assíncrona; portanto, aumente a memória do nó de JOIN de dimensão. Como regra geral, eleve a memória para o dobro do tamanho dos dados da tabela de dimensão remota.

Ajuste de um JOIN de tabela de dimensão

Categorias de parâmetros de ajuste e como transmiti-los

O ajuste de um JOIN de tabela de dimensão envolve três categorias de parâmetros. Cada categoria possui um método próprio de transmissão, e o uso do mecanismo incorreto faz com que o hint seja ignorado silenciosamente.

Categoria

Parâmetros típicos

Como transmitir

Escopo

Opções WITH do conector

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

defina na cláusula WITH (...) durante a criação da tabela ou substitua no momento da consulta com /*+ OPTIONS('key'='value') */.

Tabela única

Opções de hint LOOKUP

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

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

Operação de junção única

TableConfig no nível do job Flink

Configurações globais cujas chaves começam com table.exec.* ou table.optimizer.*

execute SET 'table.exec.async-lookup.buffer-capacity' = '3072'; no início do job.

Todo o job

Importante
  • Um hint OPTIONS() substitui apenas as opções que o conector aceita na cláusula WITH. Ele não aceita chaves TableConfig table.exec.* — chaves inválidas são ignoradas silenciosamente.

  • Um hint LOOKUP() reconhece apenas as chaves fixas listadas na tabela acima. Ele não aceita chaves de configuração completas do Flink. Por exemplo, para ajustar o buffer de lookup assíncrono, escreva 'capacity'='100'; escrever 'table.exec.async-lookup.buffer-capacity'='100' não surte efeito.

  • Para alterar um parâmetro global não exposto por nenhum hint, use SET 'xxx' = 'yyy';.

Substituir opções do conector com o hint OPTIONS

O hint OPTIONS() permite substituir as opções WITH de uma tabela diretamente em uma consulta, sem modificar a instrução CREATE TABLE. Seu uso é comum para ajustar o comportamento de cache.

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;

Toda chave dentro de OPTIONS deve ser uma opção WITH suportada pelo conector.

Nota

As opções lookup.cache e lookup.partial-cache.max-rows mostradas acima pertencem à interface genérica LookupCache do Flink (FLIP-221) e aplicam-se apenas a conectores mais recentes que implementam essa interface (como Fluss e JDBC). As estratégias None/LRU/ALL descritas na seção "Estratégias de cache para tabelas de dimensão" correspondem a conectores legados, que expõem seu comportamento de cache por meio de diferentes opções WITH. Consulte a documentação do conector alvo para confirme quais opções e estratégias de cache ele suporta, evitando o uso de parâmetros não reconhecidos pelo conector.

configure o comportamento de lookup com o hint LOOKUP

O hint LOOKUP comporta-se de maneira consistente com a versão da comunidade Apache Flink. Ele configura o modo síncrono/assíncrono, novas tentativas e o comportamento de shuffle para uma única operação de junção. Para mais detalhes, consulte Apache Flink Lookup Hint.

  • O hint LOOKUP está disponível apenas no VVR 8.0 e versões posteriores.

  • A opção 'shuffle' = 'true' está disponível apenas no VVR 8.0.8 e versões posteriores.

  • Aliases são suportados no VVR 8.0 e versões posteriores. Quando a tabela de dimensão for referenciada por um alias, o hint deve usar esse alias.

Opções suportadas

Opção

Significado

Valor

table

Nome ou alias da tabela de dimensão ao qual o hint se aplica.

String com nome ou alias da tabela.

async

Define se o lookup assíncrono deve ser ativado.

true / false

output-mode

Ordenação de saída dos lookups assíncronos.

ordered / allow_unordered

capacity

Capacidade da fila de buffer para lookups assíncronos.

Inteiro.

timeout

Tempo limite para um lookup assíncrono.

Duração (por exemplo, 180s).

retry-predicate

Condição que aciona uma nova tentativa.

Atualmente, apenas lookup_miss é suportado.

retry-strategy

Estratégia de nova tentativa.

Atualmente, apenas fixed_delay é suportado.

fixed-delay

Intervalo fixo entre novas tentativas.

Duração (por exemplo, 10s).

max-attempts

Número máximo de tentativas de nova tentativa.

Inteiro.

shuffle

Define se deve haver shuffle antes da junção com a tabela de dimensão.

true / false

Comportamento da opção shuffle

A opção shuffle afeta a estratégia de shuffle da junção com a tabela de dimensão. O comportamento efetivo em cada cenário é descrito abaixo.

Cenário

Estratégia de junção

'shuffle' = 'true' não está definido.

Usa-se a estratégia de shuffle padrão do mecanismo.

'shuffle' = 'true' não está definido e o conector de dimensão não fornece uma estratégia de junção personalizada.

Usa-se a estratégia de shuffle padrão do mecanismo.

'shuffle' = 'true' está definido e o conector de dimensão não fornece uma estratégia de junção personalizada.

SHUFFLE_HASH é usado por padrão. Para detalhes, consulte a seção SHUFFLE_HASH abaixo.

'shuffle' = 'true' está definido e o conector de dimensão fornece uma estratégia de junção personalizada.

Usa-se a estratégia de shuffle personalizada fornecida pelo conector.

Nota

Atualmente, apenas o conector Streaming Lakehouse Paimon fornece uma estratégia de shuffle personalizada. Quando as colunas de junção abrangem todas as colunas de bucket, o shuffle ocorre com base no bucket.

Exemplos 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;

Definir TableConfig no nível do job com SET

Chaves como table.exec.* e similares do TableConfig são configurações globais no nível do job. Transmita-as via SET; nem o hint LOOKUP nem o hint OPTIONS as aceitam.

Chaves comuns do TableConfig para JOIN de tabela de dimensão:

Chave

Significado

Padrão

table.exec.async-lookup.buffer-capacity

Capacidade da fila de buffer para lookups assíncronos (padrão no nível do job).

100

table.exec.async-lookup.timeout

Tempo limite para lookups assíncronos (padrão no nível do job).

3 min

table.exec.async-lookup.output-mode

Ordenação de saída dos lookups assíncronos (padrão no nível do job).

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

Quando SET e um hint LOOKUP definem o mesmo parâmetro, o hint LOOKUP na junção individual tem precedência.

Controlar shuffle com hints de estratégia de junção

Hints de estratégia de junção controlam o comportamento de shuffle para junções de tabelas de dimensão. Os hints disponíveis são SHUFFLE_HASH, REPLICATED_SHUFFLE_HASH e SKEW. A tabela abaixo mostra qual estratégia de junção é adequada para cada estratégia de cache.

Estratégia de cache

SHUFFLE_HASH

REPLICATED_SHUFFLE_HASH (equivalente a SKEW)

None

Esta estratégia não é recomendada; o fluxo principal incorre em sobrecarga de rede adicional.

Esta estratégia não é recomendada; o fluxo principal incorre em sobrecarga de rede adicional.

LRU

Considere esta estratégia quando a E/S de lookup de dimensão for o gargalo. Se o fluxo principal apresentar localidade temporal na chave de junção, isso melhora a taxa de acerto do cache, reduz solicitações de E/S e aumenta o throughput geral.

Importante

O fluxo principal incorre em sobrecarga de rede adicional. Se o fluxo principal tiver distorção (skew) na chave de junção e você encontrar um gargalo de desempenho, considere usar REPLICATED_SHUFFLE_HASH.

Considere esta estratégia quando a E/S de lookup de dimensão for o gargalo e o fluxo principal tiver distorção na chave de junção. Se houver localidade temporal na chave de junção, a taxa de acerto do cache melhora, as solicitações de E/S diminuem e o throughput geral aumenta.

ALL

Recomendada quando a memória da tabela de dimensão se tornar o gargalo. O uso de memória pode cair para 1 / paralelismo.

Importante

O fluxo principal incorre em sobrecarga de rede adicional. Se o fluxo principal tiver distorção na chave de junção e você encontrar um gargalo de desempenho, considere usar REPLICATED_SHUFFLE_HASH.

Recomendada quando a memória da tabela de dimensão for o gargalo e o fluxo principal tiver distorção na chave de junção. O uso de memória cai para contagem de buckets / paralelismo.

Importante
  • A opção shuffle do hint LOOKUP já cobre a funcionalidade do SHUFFLE_HASH. Quando ambos estão presentes, a opção shuffle do hint LOOKUP prevalece.

  • A opção shuffle do hint LOOKUP ainda não lida com distorção de dados. Quando combinada com REPLICATED_SHUFFLE_HASH ou SKEW, a estratégia especificada por REPLICATED_SHUFFLE_HASH ou SKEW tem precedência.

SHUFFLE_HASH

Efeito: O uso de uma estratégia shuffle-hash em um JOIN de tabela de dimensão realiza o shuffle do fluxo principal pela chave de junção antes da junção. Combinada com a estratégia de cache LRU, aumenta a taxa de acerto do cache e reduz solicitações de E/S; combinada com a estratégia de cache ALL, reduz o uso de memória. Um único hint SHUFFLE_HASH pode especifique várias tabelas de dimensão.

Limites: O SHUFFLE_HASH reduz o uso de memória, mas os dados upstream precisam passar por shuffle pela chave de junção, o que introduz sobrecarga de rede adicional. Evite-o nos dois casos seguintes:

  • O fluxo principal apresenta forte distorção na chave de junção. O uso de SHUFFLE_HASH tornaria o nó de junção um gargalo, causando backpressure severo em jobs de streaming ou long tails em jobs em lote. Use REPLICATED_SHUFFLE_HASH.

  • A tabela de dimensão é pequena e a estratégia de cache ALL não apresenta gargalo de memória. Nesse caso, a economia de memória proporcionada pelo SHUFFLE_HASH não compensa a sobrecarga de rede adicional.

Exemplo 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

Efeito: O REPLICATED_SHUFFLE_HASH comporta-se essencialmente como o SHUFFLE_HASH, exceto por distribuir aleatoriamente as linhas do fluxo principal com a mesma chave entre N instâncias paralelas. Isso resolve o gargalo de desempenho causado pela distorção de dados. Um único hint REPLICATED_SHUFFLE_HASH pode especifique várias tabelas de dimensão.

Limites:

  • configure a contagem de buckets para dados distorcidos com table.exec.skew-join.replicate-num (padrão: 16). Seu valor não pode exceder o paralelismo do nó de junção de dimensão. Para detalhes, consulte Ajuste de SQL no nível do job.

  • Fluxos de atualização não são suportados. O uso deste hint quando o fluxo principal é um fluxo de atualização gera um erro.

Exemplo de código:

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

SKEW

Efeito: Quando se sabe que a tabela especificada possui distorção, o otimizador aplica a estratégia replicated-shuffle-hash. SKEW é um açúcar sintático — internamente, é implementado com replicated shuffle hash.

Limites:

  • Cada hint SKEW pode especifique apenas uma tabela.

  • O nome da tabela deve referir-se à tabela principal que possui a distorção, não à tabela de dimensão.

  • Fluxos de atualização não são suportados. O uso deste hint quando o fluxo principal é um fluxo de atualização gera um erro.

Exemplo de código:

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

Exemplos

Exemplo 1: Um JOIN básico de tabela de dimensão

A forma mais básica: enriquecer um fluxo Kafka com uma tabela de dimensão MySQL. Nenhum hint de ajuste é utilizado.

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;

Exemplo 2: ative cache com o hint OPTIONS e configure lookup assíncrono com o hint LOOKUP

Cenário de ajuste: o QPS da tabela de dimensão é insuficiente. Você deseja ative o cache parcial na tabela de dimensão e habilitar o lookup assíncrono com uma fila de buffer maior.

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;
  • Opções do conector (lookup.cache, lookup.partial-cache.max-rows) são transmitidas por meio de um hint OPTIONS() posicionado logo após a referência à tabela de dimensão; isso substitui as opções WITH correspondentes no momento da consulta.

  • Comportamento de lookup (async, capacity) é configurado por meio de um hint LOOKUP() posicionado após SELECT. OPTIONS e LOOKUP são dois tipos diferentes de hints e devem ser escritos separadamente; combiná-los desativa o hint silenciosamente.

Exemplo 3: Ajustar o buffer de lookup assíncrono no nível do job com SET

Cenário de ajuste: vários JOINs de tabela de dimensão no mesmo job precisam de um buffer de lookup assíncrono maior. Você deseja que a alteração se aplique globalmente e ative o modo assíncrono via 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;
  • Parâmetros como table.exec.async-lookup.buffer-capacity são chaves TableConfig no nível do job e só podem ser definidos com SET. Inseri-los dentro de OPTIONS ou LOOKUP não surte efeito.

  • Quando o hint LOOKUP não especifique capacity, o valor global definido por SET é utilizado. Se ambos forem especificados, o hint LOOKUP tem precedência naquela junção individual.