Todos os produtos
Search
Central de documentação

PolarDB:Operadores

Última atualização: Jul 14, 2026

O PolarDB-X traduz cada instrução SQL em uma árvore de operadores antes da execução. Execute EXPLAIN em qualquer consulta para visualizar quais operadores foram escolhidos e o motivo. Esta referência descreve a função de cada operador, o significado de seus argumentos e quando o otimizador os seleciona.

Referência de operadores

Categoria

Operadores

Push down para nós de dados

LogicalView, LogicalModifyView, PhyTableOperation, IndexScan

Join

BKAJoin, NLJoin, HashJoin, SortMergeJoin, HashSemiJoin, SortMergeSemiJoin, MaterializedSemiJoin

Ordenação

MemSort, TopN, MergeSort

Agregação (GROUP BY)

HashAgg, SortAgg

Redistribuição ou coleta de dados

Exchange, Gather

Filtragem de linhas

Filter

Seleção de colunas

Project

Mesclagem de conjuntos de resultados

UnionAll, UnionDistinct

Limitação de linhas de saída

Limit

Função de janela

OverWindow

Locais de execução

Os operadores do PolarDB-X são executados em um destes dois locais:

  • Nós de dados (camada de armazenamento): Os operadores enviados via push down são executados diretamente nos shards de armazenamento, próximos aos dados. Essa estratégia reduz o volume de dados transferidos para o nó de computação e melhora o desempenho da consulta.

  • Nós de computação: Operadores que não podem ser enviados via push down — geralmente por dependerem de resultados de múltiplos shards — são executados no nó de computação após a camada de armazenamento retornar resultados parciais.

O objetivo do otimizador é delegar o máximo possível de trabalho à camada de armazenamento. Os operadores de push down (LogicalView, LogicalModifyView, PhyTableOperation, IndexScan) representam esse trabalho delegado. Todos os demais operadores são executados no nó de computação.

Operadores com push down para nós de dados

LogicalView

O operador LogicalView lê dados dos nós de dados. Trata-se do principal operador de push down para instruções SELECT, capaz de delegar um conjunto mais amplo de operações do que os operadores TableScan e IndexScan — incluindo Project, Filter, operadores de agregação, ordenação, join e subconsultas.

Um plano de execução sempre exibe o modelo SQL executado na camada de armazenamento, juntamente com a lista de shards de tabela alvo.

Quando o otimizador o utiliza: Sempre que uma instrução SELECT tem como alvo um ou mais shards, o LogicalView aparece no plano.

Exemplo

EXPLAIN SELECT * FROM sbtest1 WHERE id > 1000;

Saída:

Gather(concurrent=true)
  LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)")

Argumentos

Argumento

Descrição

tables

Shards de tabela alvo da instrução. Formato: [<db-shard-range>].<table>_[<table-shard-range>]. No exemplo, [000-127] indica os shards de tabela de 000 a 127.

shardCount

Quantidade total de shards de tabela verificados. No exemplo, 128 shards são escaneados.

sql

Modelo SQL enviado à camada de armazenamento. O PolarDB-X substitui o nome da tabela pelo nome da tabela física durante a execução e preenche os placeholders ? com valores reais. Para mais detalhes, consulte Gerenciar planos de execução.

LogicalModifyView

O LogicalModifyView grava dados nos nós de dados. Ele abrange instruções INSERT, UPDATE e DELETE, contendo os mesmos campos do LogicalView: nomes dos shards de tabela física, contagem de shards e um modelo SQL.

Quando o cache de plano de execução está ativado, as constantes no modelo SQL são substituídas por placeholders ?.

Quando o otimizador o utiliza: Sempre que uma instrução de escrita (INSERT, UPDATE ou DELETE) tem como alvo um ou mais shards, o LogicalModifyView aparece no plano.

Exemplos

EXPLAIN UPDATE sbtest1 SET c='Hello, DRDS' WHERE id > 1000;

Saída:

LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="UPDATE `sbtest1` SET `c` = ? WHERE (`id` > ?)")
EXPLAIN DELETE FROM sbtest1 WHERE id > 1000;

Saída:

LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="DELETE FROM `sbtest1` WHERE (`id` > ?)")

PhyTableOperation

O PhyTableOperation opera diretamente em um único shard de tabela física. Seu uso ocorre principalmente em instruções INSERT. Quando um SELECT é roteado para um shard de tabela, o PhyTableOperation o executa.

Em um INSERT com múltiplas linhas, cada linha recebe seu próprio PhyTableOperation.

Quando o otimizador o utiliza: Em instruções INSERT — cada linha é atribuída a exatamente um shard físico. Também é usado quando uma instrução SELECT é roteada para um shard de tabela.

Exemplo

EXPLAIN INSERT INTO sbtest1 VALUES(1, 1, '1', '1'),(2, 2, '2', '2');

Saída:

PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_001]", sql="INSERT INTO ? (`id`, `k`, `c`, `pad`) VALUES(?, ?, ?, ?)", params="`sbtest1_001`,1,1,1,1")
PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_002]", sql="INSERT INTO ? (`id`, `k`, `c`, `pad`) VALUES(?, ?, ?, ?)", params="`sbtest1_002`,2,2,2,2")

Duas linhas no INSERT geram duas entradas PhyTableOperation, uma por shard.

Argumentos

Argumento

Descrição

tables

Nome da tabela física para esta operação. Cada PhyTableOperation tem como alvo exatamente uma tabela física.

sql

Modelo SQL com o nome da tabela e constantes substituídos por placeholders ?.

params

Valores que preenchem os placeholders ? no modelo SQL, incluindo o nome da tabela física e as constantes.

IndexScan

O IndexScan lê dados dos nós de dados usando um índice secundário global (GSI) em vez da tabela base. Seu comportamento é idêntico ao do LogicalView, exceto pelo fato de escanear uma tabela de índice em vez de uma tabela base.

Quando o otimizador o utiliza: Se um predicado de consulta corresponder à chave de partição de uma coluna GSI, o otimizador usa o IndexScan para atingir apenas o shard de índice relevante, evitando uma varredura completa na tabela base. Caso não exista GSI na coluna do predicado, ou se a coluna do predicado não for uma chave de partição, o LogicalView escaneia todos os shards da tabela base.

Exemplo

EXPLAIN SELECT * FROM sequence_one_base WHERE integer_test=1;

Saída:

+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 IndexScan(tables="DRDS_POLARX1_QATEST_APP_000000_GROUP.gsi_sequence_one_index_3a0A_01", sql="SELECT `pk`, `integer_test`, `varchar_test`, `char_test`, `blob_test`, `tinyint_test`, `tinyint_1bit_test`, `smallint_test`, `mediumint_test`, `bit_test`, `bigint_test`, `float_test`, `double_test`, `decimal_test`, `date_test`, `time_test`, `datetime_test`, `timestamp_test`, `year_test`, `mediumtext_test` FROM `gsi_dml_sequence_one_index_index1` AS `gsi_dml_sequence_one_index_index1` WHERE (`integer_test` = ?)")

Neste exemplo, sequence_one_base possui um GSI chamado gsi_sequence_one_index na coluna integer_test. Como integer_test=1 corresponde à chave de partição do GSI, apenas um shard de índice é escaneado. Sem o GSI, ou se integer_test não fosse uma chave de partição, todos os shards da tabela base seriam escaneados.

Operadores que coletam ou redistribuem dados

Estes operadores são executados no nó de computação e gerenciam a movimentação de dados entre os shards e o nó de computação.

Gather

O Gather mescla resultados de múltiplos shards de tabela em um único conjunto de resultados. Ele aparece como pai do LogicalView na maioria dos planos de execução, coletando dados de todos os shards escaneados.

Quando o otimizador o utiliza: Sempre que o LogicalView escaneia múltiplos shards e o nó de computação precisa de um conjunto de resultados unificado, o Gather aparece acima do LogicalView na árvore do plano.

Exchange

O Exchange é um operador lógico que redistribui dados entre nós sem realizar computação. Ele alimenta operadores subsequentes com dados redistribuídos. Três estratégias de redistribuição são utilizadas:

Estratégia

Comportamento

Uso típico

SINGLETON

Mescla múltiplos fluxos de dados em um só

Equivalente ao Gather; usado quando um único operador subsequente precisa de todas as linhas

HASH_DISTRIBUTED

Reparticiona linhas por valor de hash nas colunas especificadas

Planos de execução de join e agregação

BROADCAST_DISTRIBUTED

Transmite uma cópia dos dados para cada nó subsequente

Planos de execução de processamento massivamente paralelo (MPP)

Quando o otimizador o utiliza: O Exchange aparece em planos de execução onde os dados devem ser redistribuídos entre nós antes que um join ou agregação possa prosseguir. A estratégia de redistribuição escolhida depende do operador subsequente: distribuição por hash para joins e agregações, broadcast para planos de execução MPP e singleton quando um único fluxo é necessário.

MergeSort

O MergeSort combina múltiplos fluxos de dados ordenados de diferentes shards em um único fluxo ordenado. O otimizador o utiliza quando uma consulta com ORDER BY abrange múltiplos shards — cada shard ordena localmente e o MergeSort mescla os resultados no nó de computação.

Quando o otimizador o utiliza: Se uma cláusula ORDER BY não puder ser atendida por um único shard, cada shard ordena suas linhas localmente (visível como ORDER BY no modelo SQL do LogicalView) e o MergeSort realiza a mesclagem final no nó de computação. Frequentemente aparece junto com LIMIT para consultas top-N eficientes.

Exemplo

EXPLAIN SELECT * FROM sbtest1 WHERE id > 1000 ORDER BY id LIMIT 5,10;

Saída:

MergeSort(sort="id ASC", offset=?1, fetch=?2)
  LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?) ORDER BY `id` LIMIT (? + ?)")

Argumentos

Argumento

Descrição

sort

Coluna e direção usadas para ordenação. ASC = ascendente, DESC = descendente. No exemplo, as linhas são ordenadas por id em ordem ascendente.

offset

Número de linhas a ignorar após a ordenação. O valor é parametrizado; o valor real no exemplo é 5.

fetch

Número máximo de linhas a retornar. O valor é parametrizado; o valor real no exemplo é 10.

UnionAll e UnionDistinct

Os operadores UnionAll e UnionDistinct mesclam dois ou mais conjuntos de resultados em um só. O UnionAll corresponde ao UNION ALL; já o UnionDistinct corresponde ao UNION DISTINCT e remove linhas duplicadas. Esses operadores podem ser executados tanto em nós de computação quanto em nós de dados, dependendo da decisão do otimizador.

Exemplo

EXPLAIN SELECT * FROM sbtest1 WHERE id > 1000
UNION DISTINCT
SELECT * FROM sbtest1 WHERE id < 200;

Saída:

UnionDistinct(concurrent=true)
  Gather(concurrent=true)
    LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)")
  Gather(concurrent=true)
    LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` < ?)")

Operadores para seleção de colunas e filtragem de linhas

Project

O Project seleciona colunas das linhas de entrada, avalia expressões e gera o resultado. Ele pode calcular expressões aritméticas, chamar funções ou retornar constantes.

Quando o otimizador o utiliza: O Project aparece sempre que as colunas de saída diferem das colunas de entrada — por exemplo, quando uma consulta seleciona colunas específicas, calcula valores derivados ou aplica funções. Predicados que podem ser avaliados na camada de armazenamento são enviados via push down para o LogicalView.

Exemplo

EXPLAIN SELECT 'Hello, DRDS', 1 / 2, CURTIME();

Saída:

Project(Hello, DRDS="_UTF-16'Hello, DRDS'", 1 / 2="1 / 2", CURTIME()="CURTIME()")

O plano lista cada coluna de saída ao lado de seu valor de origem, expressão ou função.

Filter

O Filter avalia um predicado e transmite apenas as linhas que o satisfazem. A condição mostrada no plano é o predicado aplicado no nó de computação. Predicados passíveis de avaliação na camada de armazenamento são enviados via push down para o LogicalView.

Quando o otimizador o utiliza: O Filter surge quando um predicado não pode ser enviado à camada de armazenamento — tipicamente quando depende de um valor agregado ou calculado (como uma cláusula HAVING), ou quando o predicado referencia colunas disponíveis somente após um join ou agregação no nó de computação.

Exemplo

EXPLAIN SELECT k, AVG(id) avg_id FROM sbtest1 WHERE id > 1000 GROUP BY k HAVING avg_id > 1300;

Saída:

Filter(condition="avg_id > ?1")
  Project(k="k", avg_id="sum_pushed_sum / sum_pushed_count")
    SortAgg(group="k", sum_pushed_sum="SUM(pushed_sum)", sum_pushed_count="SUM(pushed_count)")
      MergeSort(sort="k ASC")
        LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, SUM(`id`) AS `pushed_sum`, COUNT(`id`) AS `pushed_count` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`")

A condição WHERE id > 1000 não aparece no Filter porque foi enviada via push down para o LogicalView — visível como WHERE (id > ?) no modelo SQL. Apenas a condição HAVING avg_id > 1300, que depende do resultado agregado, permanece no Filter.