O recurso Partial Result Cache (PTRC) do PolarDB for MySQL melhora o desempenho de consultas ao armazenar em cache conjuntos de resultados intermediários de operadores. Isso reduz computações redundantes em operadores complexos. Este tópico descreve o conceito do PTRC, seu princípio de funcionamento, a seleção baseada em custo e o mecanismo de feedback dinâmico.
Conceitos
O PTRC armazena em cache o conjunto de resultados de um operador dentro de uma consulta. Por exemplo, ele pode guardar resultados temporários de operadores como subconsultas correlacionadas ou junções de loop aninhado (nested loop join). Se o mesmo operador for executado novamente, o sistema reutiliza o resultado em cache em vez de reexecutá-lo.
O termo "Parcial" no PTRC tem dois significados:
O PTRC armazena em cache o conjunto de resultados intermediários de um ou mais operadores dentro de uma consulta, e não o resultado da consulta inteira.
Nem sempre todo o conjunto de resultados intermediários de um operador é armazenado. Devido a limites de memória, apenas uma parte dos resultados pode ser mantida em cache.
Em comparação com um cache de consulta tradicional, o PTRC opera com granularidade mais fina e acelera operadores específicos. O cache existe apenas durante a execução da consulta. Essa abordagem oferece maior aplicabilidade. Como a otimização é interna a uma única consulta, evita problemas de consistência de dados entre nós. Qualquer operador pode usar o PTRC se produzir um resultado determinístico para um determinado conjunto de parâmetros de entrada. O otimizador decide se deve usar o PTRC com base no custo.
Princípio de funcionamento
A ideia central do PTRC é armazenar em cache os conjuntos de resultados intermediários dos operadores para evitar execuções redundantes. O PTRC acelera um operador se as seguintes condições forem atendidas:
O operador depende de parâmetros correlacionados para sua execução e é executado várias vezes. Exemplos incluem operadores de junção de loop aninhado e subconsulta correlacionada.
Para os mesmos parâmetros correlacionados, o resultado do operador é sempre idêntico. Por exemplo, o operador não pode conter funções não determinísticas como
RANDOM(),NOW()ou funções definidas pelo usuário (UDFs). O uso dessas funções comprometeria a correção do resultado final.
Parâmetros correlacionados são parâmetros externos dos quais um operador depende durante sua execução. Por exemplo, em uma operação de junção t1 join t2 on t1.a = t2.a, se a tabela t1 for a tabela condutora, cada linha dela será unida à tabela t2. Nesse caso, t1.a é considerado um parâmetro correlacionado para o operador de junção de loop aninhado. Se a coluna t1.a na tabela t1 contiver muitos valores duplicados, o PTRC poderá reduzir a computação redundante. Outro exemplo é uma subconsulta correlacionada, em que cada execução depende de um valor da consulta externa.
A consulta TPC-H Q17 ilustra o funcionamento do PTRC:
SELECT
sum(l_extendedprice) / 7.0 AS avg_yearly
FROM
lineitem,
part
WHERE
p_partkey = l_partkey
AND p_brand = 'Brand#34'
AND p_container = 'MED BOX'
AND l_quantity < (
SELECT
0.2 * avg(l_quantity)
FROM
lineitem
WHERE
l_partkey = p_partkey
);
O PTRC usa os parâmetros correlacionados do operador como chave e o resultado da execução como valor. Para a TPC-H Q17, o formato do cache PTRC é: chave = p_partkey, valor = [true/false].
A figura a seguir mostra o fluxo principal de execução do PTRC para a subconsulta correlacionada na TPC-H Q17:
Sempre que a subconsulta correlacionada é avaliada, o sistema busca o resultado no cache PTRC usando o valor de p_partkey:
Se o resultado não for encontrado (cache miss), o sistema executa a subconsulta e armazena o resultado no cache PTRC.
Se o resultado for encontrado (cache hit), o sistema retorna o valor em cache diretamente e evita uma execução redundante da subconsulta.
Na TPC-H Q17, a subconsulta é executada após a união das tabelas part e lineitem. O resultado dessa junção contém muitos valores duplicados para p_partkey, que é o parâmetro correlacionado da subconsulta. Consequentemente, o PTRC atinge uma taxa de acerto de cache muito alta e gera ganhos significativos de desempenho.
Use o comando EXPLAIN para visualizar o plano de execução. Um operador Partial Result Cache no plano de execução antes da subconsulta indica que o PTRC está em uso. Por exemplo, na saída do EXPLAIN para a TPC-H Q17, Partial result cache: keys(part.P_PARTKEY) é o nó de cache PTRC.
*************************** 1. row ***************************
EXPLAIN: -> Aggregate: sum(lineitem.L_EXTENDEDPRICE)
-> Nested loop inner join (cost=743267.04 rows=509876)
-> Filter: ((part.P_CONTAINER = 'MED BOX') and (part.P_BRAND = 'Brand#34')) (cost=204145.06 rows=19096)
-> Table scan on part (cost=204145.06 rows=1909557)
-> Filter: (lineitem.L_QUANTITY < (select #2)) (cost=25.56 rows=27)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=25.56 rows=27)
-> Select #2 (subquery in condition; dependent)
-> Partial result cache: keys(part.P_PARTKEY)
-> Aggregate: avg(lineitem.L_QUANTITY)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=28.23 rows=27)
Pré-requisitos
Seu cluster PolarDB for MySQL deve ser da versão 8.0, com revisão 8.0.2.2.9 ou posterior. Verifique a versão do seu cluster seguindo as instruções em Versões do mecanismo de consulta.
Parâmetros
|
Parâmetro |
Nível |
Descrição |
|
partial_result_cache_enabled |
Global/Sessão |
Ativa ou desativa o recurso Partial Result Cache (PTRC). Valores válidos:
|
|
partial_result_cache_cost_threshold |
Global/Sessão |
Limiar de custo para o PTRC. O otimizador só considera o uso do PTRC se o custo total de uma consulta exceder esse limiar. Faixa de valores: 0 a 18446744073709551615. Valor padrão: 10000. |
|
partial_result_cache_check_frequency |
Global/Sessão |
Frequência de acionamento do mecanismo de feedback dinâmico. Uma verificação ocorre quando o número acumulado de falhas de cache (cache misses) atinge esse valor. Faixa de valores: 0 a 18446744073709551615. Valor padrão: 200. |
|
partial_result_cache_low_hit_rate |
Global/Sessão |
Limiar inferior (low watermark) para a taxa de acerto de cache. O otimizador considera o uso do PTRC somente se a taxa de acerto estimada estiver acima desse valor. Se o PTRC já estiver em uso, o mecanismo de feedback dinâmico o desativará caso a taxa de acerto real caia abaixo desse limiar. Faixa de valores: 0 a 100. Valor padrão: 20. |
|
partial_result_cache_high_hit_rate |
Global/Sessão |
Limiar superior (high watermark) para a taxa de acerto de cache. Quando o uso de memória atinge seu limite e a taxa de acerto está acima desse valor, o sistema move o cache da memória para o armazenamento em disco. Os dados existentes em cache também são movidos para o disco. Faixa de valores: 0 a 100. Valor padrão: 70. |
|
partial_result_cache_max_mem_size |
Global/Sessão |
Quantidade acumulada de memória que o PTRC pode usar para uma única consulta. Se uma consulta contiver vários operadores que usam PTRC, o uso combinado de memória não poderá exceder esse limite. Faixa de valores: 0 a 18446744073709551615. Unidade: Bytes. Valor padrão: 67108864. |
Seleção baseada em custo
Conforme demonstrado no fluxo de execução do PTRC, ativar esse recurso nem sempre é benéfico. Sua eficácia depende da taxa de acerto de cache. Se a taxa de acerto for baixa, o PTRC pode adicionar sobrecarga de desempenho devido a operações como verificações de cache e aumento no consumo de memória.
Para evitar sobrecarga desnecessária, o otimizador usa uma abordagem baseada em custo para decidir se deve usar o PTRC. Ele avalia dois fatores principais:
O otimizador considera o uso do PTRC apenas se o custo total da consulta exceder o valor de
partial_result_cache_cost_threshold.A taxa de acerto de cache estimada para o operador deve ser superior ao valor de
partial_result_cache_low_hit_rate.
Ao tomar uma decisão baseada em custo, o otimizador verifica primeiro o parâmetro partial_result_cache_cost_threshold.
Se o custo total de uma consulta estiver abaixo desse limiar, o otimizador considera a consulta de baixo custo e com provável execução rápida. O ganho de desempenho com o PTRC seria mínimo, e a sobrecarga das verificações de cache poderia aumentar a latência em consultas curtas e de alta concorrência. Portanto, o otimizador usa esse limiar de custo global para ignorar completamente o PTRC em consultas econômicas. Isso também poupa o otimizador da sobrecarga de avaliar todas as expressões quanto à elegibilidade para o PTRC.
-
Se o custo total da consulta for maior ou igual a
partial_result_cache_cost_threshold, o otimizador avalia todos os operadores elegíveis para o PTRC e estima sua taxa de acerto de cache usando a seguinte fórmula:hit_rate = (fanout - ndv) / fanoutNesta fórmula,
fanouté o número total de execuções esperadas de um operador, endvé o número de valores distintos para a chave PTRC, que corresponde à combinação de todos os parâmetros correlacionados.
Se a hit_rate estimada for inferior ao valor de partial_result_cache_low_hit_rate, o otimizador não usará o PTRC para esse operador. No entanto, no modelo de custo atual do MySQL, as estatísticas dependem de índices de tabela ou dados de histograma. Se as colunas dos parâmetros correlacionados não tiverem índice ou histograma, o otimizador não conseguirá estimar o ndv com precisão. Nesses casos, o otimizador pode ativar proativamente o PTRC e confiar no mecanismo de feedback dinâmico durante a execução para determinar se deve continuar usando-o.
Mecanismo de feedback dinâmico
Durante a fase de execução, cada acerto ou falha de cache é registrado nas estatísticas. O mecanismo de feedback dinâmico usa essas informações para calcular a taxa real de acerto de cache. Se a taxa real cair abaixo do valor de partial_result_cache_low_hit_rate, o mecanismo desativa imediatamente o PTRC pelo restante da execução. Isso reverte a consulta para seu plano de execução original e reduz a sobrecarga causada por um cache ineficiente.
O parâmetro partial_result_cache_check_frequency controla a frequência da verificação dinâmica. Ele especifica o número de falhas de cache acumuladas que disparam uma verificação. Por exemplo, com o valor padrão de 200, o mecanismo de feedback dinâmico é acionado após 200 falhas de cache.
Como o conjunto de resultados é armazenado em cache na memória, o mecanismo de feedback dinâmico também é acionado quando o uso de memória do PTRC atinge seu limite. Nesse cenário, o mecanismo não apenas verifica se a taxa de acerto de cache está muito baixa, mas também decide se deve realizar evicção de dados ou descarregar (spill) o conjunto de resultados para o disco.
Quando o uso de memória do PTRC atinge seu limite, aplica-se a seguinte política de feedback:
Se a
hit_rateestiver abaixo do valor departial_result_cache_low_hit_rate, o sistema considera a taxa de acerto muito baixa e desativa o PTRC.Se a
hit_rateestiver acima do valor departial_result_cache_high_hit_rate, o sistema move os dados do cache da memória para o armazenamento em disco. Ainda se espera uma melhoria previsível de desempenho mesmo com o cache baseado em disco.Se a
hit_rateestiver entre os limiares inferior e superior, o sistema aciona uma política de evicção de dados LRU (Least Recently Used). Os dados usados menos recentemente são removidos do cache para liberar espaço para novos dados. Se o limite de memória for atingido novamente após o armazenamento de novos dados em cache, o processo se repete, começando pela etapa 1.
O parâmetro partial_result_cache_max_mem_size limita o uso acumulado de memória para o PTRC dentro de uma única consulta. Se a memória total usada por todas as instâncias de PTRC em uma consulta exceder esse limite, o sistema acionará o mecanismo de feedback dinâmico para todas elas.
Teste de desempenho
Conforme discutido na seção de seleção baseada em custo, os principais fatores que afetam os benefícios de desempenho do PTRC são:
O custo de execução do operador acelerado deve ser suficientemente alto. Se o próprio operador for barato de executar, o ganho potencial de desempenho com o cache será limitado.
A taxa de acerto de cache deve ser alta, pois uma taxa maior gera melhorias de desempenho mais significativas.
Tome o teste TPC-H Q17 como exemplo:
SELECT sum(l_extendedprice) / 7.0 AS avg_yearly
FROM lineitem, part
WHERE p_partkey = l_partkey
AND p_brand = 'Brand#34'
AND p_container = 'MED BOX'
AND l_quantity < (
SELECT 0.2 * avg(l_quantity)
FROM lineitem
WHERE l_partkey = p_partkey
);
A subconsulta nesta consulta é executada muitas vezes. O plano de execução a seguir mostra que o PTRC está em uso. Na árvore EXPLAIN para a TPC-H Q17, o nó Partial result cache: keys(part.P_PARTKEY) indica que o PTRC foi aplicado à subconsulta dependente:
EXPLAIN: -> Aggregate: sum(lineitem.L_EXTENDEDPRICE)
-> Nested loop inner join (cost=743267.04 rows=509876)
-> Filter: ((part.P_CONTAINER = 'MED BOX') and (part.P_BRAND = 'Brand#34')) (cost=204145.06 rows=19096)
-> Table scan on part (cost=204145.06 rows=1909557)
-> Filter: (lineitem.L_QUANTITY < (select #2)) (cost=25.56 rows=27)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=25.56 rows=27)
-> Select #2 (subquery in condition; dependent)
-> Partial result cache: keys(part.P_PARTKEY)
-> Aggregate: avg(lineitem.L_QUANTITY)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=28.23 rows=27)
Estatísticas de teste mostram que a ativação do PTRC para a subconsulta na TPC-H Q17 atinge uma taxa de acerto de cache de até 96%, o que resulta em uma melhoria significativa de desempenho. A figura a seguir mostra os dados do teste:
Resumo
O PTRC visa operadores complexos dentro de uma única consulta que dependem de parâmetros correlacionados. Ao armazenar em cache os conjuntos de resultados intermediários desses operadores, ele reduz computações redundantes. É possível obter ganhos substanciais de desempenho se a taxa de acerto de cache for alta o suficiente. Atualmente, o PTRC pode acelerar vários operadores, incluindo subconsultas correlacionadas e junções de loop aninhado (o que abrange inner joins, outer joins, semi-joins e anti-joins).