IBM Cloud Docs
Pushdown JDBC

Pushdown JDBC

IBM Presto pode transferir o processamento de consultas de união ou parte delas para a fonte de dados conectada JDBC.

Operação de união

Presto transforma as consultas de união em uma representação interna específica (operação de união) chamada 'PlanNode'. Com o uso eficaz da operação de união e das técnicas de otimização de consultas, o site Presto executa consultas de união complexas com eficiência.

Junte-se ao pushdown

Presto permite que o conector delegue a operação "Join ( PlanNode )" à fonte de dados subjacente JDBC. O conector deve ser capaz de processar o predicado de união no nível da fonte de dados. Esse processo, conhecido como "join pushdown", melhora significativamente o desempenho da consulta.

Otimização de consulta

Presto analisa as consultas de união para criar uma "operação de união ( PlanNode )" ideal. Esse processo de otimização envolve a inferência e a reestruturação da consulta para melhorar o desempenho.

A seguir, alguns exemplos de Presto inferencing que fazem diferença estrutural na consulta de união:

Presto inferências
Presto inferências Consulta fornecida pelo usuário Resultado da consulta de inferências
Inferências para remover a condição de união select * from postgresql.pg.mypg_table1 t1
join postgresql.pg.mypg_table2 t2 on
t1.pgfirsttablecolumn=t2.pgsecondtablecolumn
where t1.pgfirsttablecolumn=100
select * from postgresql.pg.mypg_table1
t1,postgresql.pg.mypg_table2 t2 where
t1.pgfirsttablecolumn=100 and
t2.pgfirsttablecolumn=100
Inferências para criar junções internas a partir de junções à direita, à esquerda ou cruzadas SELECT e.first_name_varchar,
p.project_name_varchar, p.risk_level_tinyint
FROM mysql.tm_lakehouse_engine_db_1.employee
e CROSS JOIN
mysql.tm_lakehouse_engine_db_1.projects p
WHERE e.age_tinyint > p.risk_level_tinyint;
SELECT e.first_name_varchar,
p.project_name_varchar,
p.risk_level_tinyint FROM
mysql.tm_lakehouse_engine_db_1.employee
e,
mysql.tm_lakehouse_engine_db_1.projects
p WHERE e.age_tinyint >
p.risk_level_tinyint;

As uniões à esquerda e à direita podem ser convertidas internamente em uniões internas e podem ser empurradas para um conector específico. Além disso, existe um caso em que as uniões internas podem não ser empurradas para baixo em direção a um conector específico devido a algumas condições.

Principais considerações sobre o pushdown da consulta Join em Presto JDBC data source

Presto valida as especificações de 'join operation( PlanNode )' para executar 'join pushdown'. Essas especificações variam para cada fonte de dados e conector. No entanto, a seguir estão algumas condições genéricas a serem atendidas para que um join seja empurrado para baixo em um conector JDBC.

  • Suporte do conector: O conector JDBC deve ser capaz de processar a operação de união. Operações complexas envolvendo funções ou operadores do Presto podem impedir o pushdown.
  • Tipo e condições da união: A união deve ser normalmente uma união interna com pelo menos uma coluna comum entre as tabelas. As condições de união devem envolver tipos de dados e operadores compatíveis.
  • Compatibilidade com o banco de dados: O banco de dados subjacente deve ser compatível com a operação de união específica e com os tipos de dados envolvidos. Para obter mais informações, consulte Tipos de dados e operadores que suportam o recurso de pushdown de união.
  • Agrupamento de tabelas: As tabelas do mesmo conector e que atendem aos critérios exigidos podem ser agrupadas para pushdown.
  • Configuração: O pushdown de união é controlado por meio de uma combinação de propriedades em nível de sessão.

Para ativar o pushdown de ingresso, defina os seguintes sinalizadores de sessão:

Permite o pushdown para fontes de dados elegíveis, mas só funcionará para equi-joins (uniões com condições de igualdade)

SET SESSION optimizer_inner_join_pushdown_enabled = true;

Habilita o pushdown para uniões não equitativas (uniões com desigualdade ou condições baseadas em intervalo) para fontes de dados qualificadas. Precisa ser definido como true junto com o sinalizador acima.

SET SESSION optimizer_inequality_join_pushdown_enabled = true;

Habilita o pushdown de predicado parcial no nível do catálogo. Isso permite que as condições de filtro aplicáveis sejam transferidas para a fonte de dados juntamente com as cláusulas de união.

SET SESSION <catalogName>.partial_predicate_push_down = true;

Por exemplo,

SET SESSION postgresql.partial_predicate_push_down = true;

Embora isso não seja obrigatório, é recomendado, pois determinadas consultas dependem desse sinalizador para que o pushdown seja eficaz.

Por exemplo, quando você usa alguma agregação, operação matemática ou conversão de tipo de dados junto com a consulta de união, ela é convertida em funções Presto e aplicada à operação de "união". Para qualquer consulta "join" que crie uma função Presto intermediária, essa consulta não pode ser tratada pelo conector e, portanto, o push down não é executado.

Exemplo de consulta
Exemplo Consultar
Para a consulta que cria a função Presto abs(int_clumn)=int_column2;
int_sum_column=int_value1_column1+int_value1_column2
cast(varchar_20_column, varchar(100) )=varchar100_column

Verificação do pushdown de união

Para verificar se uma consulta de união foi transferida para a fonte de dados subjacente, você pode examinar o plano EXPLAIN da consulta.

Considere os seguintes pontos para verificar se uma consulta de união foi transferida para a fonte de dados subjacente:

  • Se o plano não mostrar um operador "join", isso significa que ocorreu um pushdown completo.
  • Se houver um número menor de operadores de união do que a consulta de união original, isso significa que ocorreu um pushdown parcial.
  • Se o número de operadores de união for igual ao da consulta original, isso significa que não houve pushdown.

O exemplo a seguir explica a verificação dos resultados do pushdown de união:

Consulta de união:

SELECT order_id, c_customer_id FROM postgresql.public.orders o INNER JOIN postgresql.public.customer c ON c.c_customer_id=o.customer_id;

Plano original Presto:

- Output[PlanNodeId 9][order_id, c_customer_id] => [order_id:integer, c_customer_id:char(16)]
 - RemoteStreamingExchange[PlanNodeId 266][GATHER] => [order_id:integer, c_customer_id:char(16)]
     - InnerJoin[PlanNodeId 4][(""customer_id"" = ""c_customer_id"")][$hashvalue, $hashvalue_11] => [order_id:integer, c_customer_id:char(16)]
             Distribution: PARTITIONED
         - RemoteStreamingExchange[PlanNodeId 264][REPARTITION][$hashvalue] => [customer_id:char(16), order_id:integer, $hashvalue:bigint]
                 Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: ?}
             - ScanProject[PlanNodeId 0,326][table = TableHandle {connectorId='postgresql', connectorHandle='JdbcTableHandle{connectorId=postgresql, schemaTableName=public.orders, catalogName=null, schemaName=public, tableName=orders, joinTables=Optional.empty}', layout='Optional[{domains=ALL, additionalPredicate={}}]'}, projectLocality = LOCAL] => [customer_id:char(16), order_id:integer, $hashvalue_10:bigint]
                     Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: 0.00}/{source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: 0.00}
                     $hashvalue_10 := combine_hash(BIGINT'0', COALESCE($operator$hash_code(customer_id), BIGINT'0')) (3:6)
                     LAYOUT: {domains=ALL, additionalPredicate={}}
                     order_id := JdbcColumnHandle{connectorId=postgresql, columnName=order_id, jdbcTypeHandle=JdbcTypeHandle{jdbcType=4, jdbcTypeName=int4, columnSize=10, decimalDigits=0, arrayDimensions=null}, columnType=integer, nullable=true, comment=Optional.empty} (3:6)
                     customer_id := JdbcColumnHandle{connectorId=postgresql, columnName=customer_id, jdbcTypeHandle=JdbcTypeHandle{jdbcType=1, jdbcTypeName=bpchar, columnSize=16, decimalDigits=0, arrayDimensions=null}, columnType=char(16), nullable=true, comment=Optional.empty} (3:6)
         - LocalExchange[PlanNodeId 297][HASH][$hashvalue_11] (c_customer_id) => [c_customer_id:char(16), $hashvalue_11:bigint]
                 Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: ?}
             - RemoteStreamingExchange[PlanNodeId 265][REPARTITION][$hashvalue_12] => [c_customer_id:char(16), $hashvalue_12:bigint]
                     Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: ?}
                 - ScanProject[PlanNodeId 1,327][table = TableHandle {connectorId='postgresql', connectorHandle='JdbcTableHandle{connectorId=postgresql, schemaTableName=public.customer, catalogName=null, schemaName=public, tableName=customer, joinTables=Optional.empty}', layout='Optional[{domains=ALL, additionalPredicate={}}]'}, projectLocality = LOCAL] => [c_customer_id:char(16), $hashvalue_13:bigint]
                         Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: 0.00}/{source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: 0.00}
                         $hashvalue_13 := combine_hash(BIGINT'0', COALESCE($operator$hash_code(c_customer_id), BIGINT'0')) (4:12)
                         LAYOUT: {domains=ALL, additionalPredicate={}}
                         c_customer_id := JdbcColumnHandle{connectorId=postgresql, columnName=c_customer_id, jdbcTypeHandle=JdbcTypeHandle{jdbcType=1, jdbcTypeName=bpchar, columnSize=16, decimalDigits=0, arrayDimensions=null}, columnType=char(16), nullable=true, comment=Optional.empty} (4:12)

Pushdown Presto plan:

- Output[PlanNodeId 9][order_id, c_customer_id] => [order_id:integer, c_customer_id:char(16)]
     Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: ?}
 - RemoteStreamingExchange[PlanNodeId 261][GATHER] => [order_id:integer, c_customer_id:char(16)]
         Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: ?}
     - TableScan[PlanNodeId 287][TableHandle {connectorId='postgresql', connectorHandle='JdbcTableHandle{connectorId=postgresql, schemaTableName=public.orders, catalogName=null, schemaName=public, tableName=orders, joinTables=Optional[[JdbcTableHandle{connectorId=postgresql, schemaTableName=public.orders, catalogName=null, schemaName=public, tableName=orders, joinTables=Optional.empty}, JdbcTableHandle{connectorId=postgresql, schemaTableName=public.customer, catalogName=null, schemaName=public, tableName=customer, joinTables=Optional.empty}]]}', layout='Optional[{domains=ALL, additionalPredicate={}}]'}] => [customer_id:char(16), order_id:integer, c_customer_id:char(16)]
             Estimates: {source: CostBasedSourceInfo, rows: ? (?), cpu: ?, memory: 0.00, network: 0.00}
             LAYOUT: {domains=ALL, additionalPredicate={}}
             c_customer_id := JdbcColumnHandle{connectorId=postgresql, columnName=c_customer_id, jdbcTypeHandle=JdbcTypeHandle{jdbcType=1, jdbcTypeName=bpchar, columnSize=16, decimalDigits=0, arrayDimensions=null}, columnType=char(16), nullable=true, comment=Optional.empty} (4:12)
             customer_id := JdbcColumnHandle{connectorId=postgresql, columnName=customer_id, jdbcTypeHandle=JdbcTypeHandle{jdbcType=1, jdbcTypeName=bpchar, columnSize=16, decimalDigits=0, arrayDimensions=null}, columnType=char(16), nullable=true, comment=Optional.empty} (3:6)
             order_id := JdbcColumnHandle{connectorId=postgresql, columnName=order_id, jdbcTypeHandle=JdbcTypeHandle{jdbcType=4, jdbcTypeName=int4, columnSize=10, decimalDigits=0, arrayDimensions=null}, columnType=integer, nullable=true, comment=Optional.empty} (3:6)

Condições para ativar o pushdown de ingresso em JDBC

JDBC o pushdown de união torna as consultas mais rápidas, às vezes até 10 vezes mais rápidas. No entanto, é importante usá-lo com cuidado. Se usado incorretamente, pode tornar o processamento da consulta mais lento.

Veja a seguir as principais considerações para habilitar o pushdown de ingresso do JDBC:

  • Se você tiver apenas um número limitado de registros, pois a operação de união resulta de tabelas enormes:

    • A união deve retornar um subconjunto relativamente pequeno de registros de tabelas grandes.
    • As condições ideais de união normalmente retornam menos de 10% do total de registros.
  • Evitar junções cruzadas:

    • Se os critérios de união levarem a um resultado de união cruzada, você não deverá usar os recursos de pushdown de união. As junções cruzadas (que produzem o produto cartesiano de duas tabelas) podem prejudicar o desempenho.
  • Otimização do banco de dados:

    • O sistema de banco de dados deve ser otimizado para lidar com as consultas de junção de forma eficiente, especialmente as junções não equitativas. Presto é capaz de realizar pushdown de junção para condições de equi-join (=) e para condições de não equi-join (<, >, <=, >=,!=, <>). Quase todos os bancos de dados são capazes de lidar com o equi-join de forma eficaz. Mas nem todos os bancos de dados são otimizados para condições de união não equitativa.
  • Agregação:

    • Somente as consultas selecionadas são empurradas para baixo. Uma consulta que faz agregação (por exemplo, select count()) não é empurrada para baixo e pode afetar o desempenho.

É possível ver ganhos de desempenho à medida que o número de linhas da tabela aumenta e o resultado da união se restringe a menos de 10% do total de registros. Veja as estatísticas a seguir para entender o comportamento:

Presto inferências
Consulta de junção Consulta de junção Melhoria de desempenho
SELECT A.ASSIGNMENT_ID, A.ROLE,
A.IS_CURRENT, B.ASSIGNMENT_ID,
B.DEFAULT_INT FROM
DB2.DB2.ASSIGNMENTS A JOIN
DB2.DB2.STUDENT B ON
A.ASSIGNMENT_ID = B.ASSIGNMENT_ID;
Ao unir tabelas:
ASSIGNMENTS com 10 milhões de linhas e
STUDENT com 5000 linhas
Join Result is 50 rows.
5x
SELECT A.ASSIGNMENT_ID, A.ROLE,
A.IS_CURRENT, B.ASSIGNMENT_ID,
B.DEFAULT_INT FROM
DB2.DB2.ASSIGNMENTS A JOIN
DB2.DB2.STUDENT B ON
A.ASSIGNMENT_ID = B.ASSIGNMENT_ID;
Ao unir tabelas:
ASSIGNMENTS com 20 milhões de linhas e
STUDENT com 5000 linhas
Join Result is 50 rows.
10x

As estatísticas mostradas na tabela são um exemplo aproximado; há uma chance de variações de valor com base no banco de dados e no ambiente.

Tipos de dados e operadores que suportam o pushdown de união

Os seguintes tipos de dados e operadores suportam o recurso de pushdown de união:

Tipos de dados suportados
Tipos de dados Operadores
BigInt =, <, >, <=, >=,!= e <>
Booleano =, !=, <>
Número inteiro =, <, >, <=, >=,!= e <>
TINYINT =, <, >, <=, >=,!= e <>
SMALLINT =, <, >, <=, >=,!= e <>
Ponto flutuante =, <, >, <=, >=,!= e <>
REAL =, <, >, <=, >=,!= e <>
DOUBLE =, <, >, <=, >=,!= e <>
DECIMAL =, <, >, <=, >=,!= e <>
VARCHAR =, <, >, <=, >=,!= e <>
CARACT =, <, >, <=, >=,!= e <>

União federada pushdown

Uma junção federada é uma consulta de junção que contém tabelas de vários catálogos.

Em uma união federada, o Presto agrupa tabelas com base em seu catálogo JDBC para otimizar o pushdown. No entanto, o pushdown só é possível se:

  • JDBC fonte de dados: As tabelas são de uma fonte de dados JDBC.
  • Especificações de pushdown: A operação de união atende aos requisitos específicos de pushdown, como tipos de dados e operadores compatíveis. Para obter mais informações, consulte Principais considerações sobre o pushdown da consulta Join em Presto JDBC data source.

Se uma tabela não atender a esses critérios, ela será excluída do pushdown e processada diretamente pelo site Presto. A tabela a seguir mostra um exemplo de união federada:

Exemplo
União Federada
SELECIONAR
i1.customer_last_name, A.ASSIGNMENT_ID, B.FIRST_NAME, t2.custkey
FROMDB2_CATALOG.DB2.ASSIGNMENTS_10_MILLION A
JOINDB2_CATALOG.DB2.CUSTOMER_10_MILLION BONA.EMPLOYEE_ID = B.CUST_ID
JOINDB2_CATALOG.DB2.JOIN_TABLE_50_ROWS CONA.ASSIGNMENT_ID = C.ASSIGNMENT_ID
JOINpostgres_catalog.pg.customer t1onB.CUST_ID = t1.custkey
Joinpostgres_catalog.pg.orders t2ONt1.custkey = t2.orderkey
Joinpostgres_catalog.pg.products t3ONt3.productkey = t2.productkey
JOINiceberg_catalog.ice.customer i1ONi1.customer = B.CUST_ID
Aqui, a consulta tem 3 catálogos: db2_catalog, postgres_catalog e iceberg_catalog.
db2_catalog ( db2 catalog) tem 3 tabelas
postgres_catalog (postgres catalog) tem 3 tabelas
iceberg_catalog (iceberg catalog) tem 1 tabela

Para a consulta de união federada anterior, o otimizador de pushdown de união cria a operação de união para os catálogos db2_catalog e posgres_catalog, conforme mostrado na tabela a seguir. Como o iceberg_catalog não é uma fonte de dados do site JDBC, ele será ignorado e retornará ao site Presto para processamento.

Exemplo
Campo Descrição
Representação de DB2_CATALOG Join Operation que é criada pelo otimizador de pushdown de junção Selecione t2.custkey From
DB2_CATALOG.DB2.ASSIGNMENTS_10_MILLION A,
DB2_CATALOG.DB2.CUSTOMER_10_MILLION B,
DB2_CATALOG.DB2.JOIN_TABLE_50_ROWS C where
A.EMPLOYEE_ID = B.CUST_ID and A.ASSIGNMENT_ID =
C.ASSIGNMENT_ID;
Representação de posgres_catalog Join Operation O otimizador de junção pushdown cria Selecione A.ASSIGNMENT_ID, B.FIRST_NAME From
posgres_catalog.pg.customer t1,
posgres_catalog.pg.orders t2,
posgres_catalog.pg.products t3 where t1.custkey =
t2.orderkey and t3.productkey = t2.productkey;

Após a otimização do pushdown de união, a consulta federada anterior é processada pelo site Presto da seguinte forma:

select i1.customer_last_name, A.ASSIGNMENT_ID, B.FIRST_NAME, t2.custkey from (result of DB2_CATALOG Join pushdown) join ( result of posgres_catalog Join pushdown) on B.CUST_ID = t1.custkey join iceberg_catalog.ice.customer i1ONi1.customer = B.CUST_ID

Lista de fontes de dados que suportam o pushdown de união

As fontes de dados a seguir suportam o recurso de pushdown de união:

  • IBM Db2
  • PostgreSQL
  • Informix
  • IBM Netezza
  • MySQL
  • Oracle
  • SQL Server
  • Teradata
  • Amazon Redshift
  • SingleStore
  • Snowflake
  • HANA
  • Apache Phoenix

Benefícios do join pushdown

Veja a seguir os benefícios do recurso pushdown de junção:

  • Melhoria no desempenho geral da consulta.
  • Redução do tráfego de rede entre o IBM presto e a fonte de dados.
  • Redução da carga na fonte de dados remota.
  • Redução significativa de custos devido ao número limitado de bancos de dados atingidos.

Limitações do pushdown de união

A seguir estão as limitações do recurso de pushdown de junção:

  • Dependência do pushdown de filtro: O pushdown de união depende dos recursos existentes de pushdown de filtro do banco de dados subjacente. Quaisquer limitações ou ineficiências no pushdown do filtro afetam o desempenho do pushdown da união.
  • Compatibilidade com o banco de dados: O join pushdown é limitado a consultas que o banco de dados subjacente pode entender. Consultas complexas que envolvam filtros, projeções, condições ou palavras-chave especiais não podem ser reduzidas.
  • Limitações do Self-Join: A implementação atual dos autoadesões não é ideal e depende do cache do manipulador de tabela. Por padrão, o cache de manipulador de tabela está desativado em Presto e, se estiver ativado, o pushdown de autoadesão falhará.

Exibindo o recurso JDBC Pushdown na interface do usuário

  1. Faça login na instância watsonx.data.
  2. Vá para Configurações.
  3. Clique na caixa de seleção JDBC. A página de detalhes do pushdown JDBC é aberta.
  4. Clique no link Documentação para saber mais sobre o recurso JDBC pushdown em watsonx.data.