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 | 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 | 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:
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 | 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:
União Federada |
---|
SELECIONARi1.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.
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
- Faça login na instância watsonx.data.
- Vá para Configurações.
- Clique na caixa de seleção JDBC. A página de detalhes do pushdown JDBC é aberta.
- Clique no link Documentação para saber mais sobre o recurso JDBC pushdown em watsonx.data.