【GaussDB (para MySQL)】 Otimização de consulta Big IN

Este artigo é compartilhado pela Huawei Cloud Community " [Coluna de tecnologia MySQL] GaussDB (para MySQL) Big IN Query Optimization ", autor: banco de dados GaussDB.

20240508-164135(WeLinkPC).jpg

Introdução ao histórico

Em um ambiente de produção, muitas vezes encontramos instruções SQL de negócios do cliente para filtragem e consulta e, em seguida, realizamos processamento de agregação, e a lista de predicados IN contém milhares ou até dezenas de milhares de valores constantes. Conforme mostrado abaixo, o tempo de execução de tais instruções é muito longo.

 

111.PNG

Otimização MySQL

Quando o MySQL de código aberto processa a coluna IN (const1, const2, ....), se houver um índice na coluna, o otimizador selecionará a varredura de intervalo para varredura, caso contrário, usará a varredura completa da tabela. A variável de sistema range_optimizer_max_mem_size controla a memória máxima que pode ser usada durante a análise do processo de otimização de intervalo. Se houver muitos elementos da lista no predicado IN, o conteúdo de cada IN será tratado como OR. Cada OR ocupará aproximadamente 230 bytes. Se o uso de memória exceder a memória máxima definida, a otimização do intervalo falhará e o otimizador alterará a estratégia, como a conversão para uma varredura completa da tabela, fazendo com que o desempenho da consulta diminua.

Para este problema de otimização, ele pode ser resolvido ajustando range_optimizer_max_mem_size. A memória definida por range_optimizer_max_mem_size está no nível da sessão. Cada sessão que executa este tipo de instrução ocupará a mesma memória. Em cenários de grande simultaneidade, isso levará ao uso excessivo da memória da instância e ao risco de OOM da instância.

Para consultas de intervalo, o MySQL define a variável de sistema eq_range_index_dive_limit para controlar se o otimizador executa mergulho de índice (índice div) ao processar consultas de intervalo equivalentes. O mergulho no índice usa o índice para completar a descrição do número de tuplas, o que pode obter informações mais precisas e otimizar melhor a estratégia de consulta, mas o tempo de execução também é longo. Quando o número de combinações IN excede um determinado número, o mergulho de índice não é aplicável. O sistema usa valores de informações estatísticas de índice estático para selecionar os índices. Isso pode fazer com que o MySQL não consiga fazer bom uso do índice, resultando em regressão de desempenho.

Grande otimização IN do GaussDB (para MySQL)

 
GaussDB (para MySQL) O método de problema de desempenho Big IN converte grandes predicados IN em subconsultas IN. Portanto, a forma do predicado IN é:
coluna IN (const1, const2, ....)
Converta para a subconsulta IN correspondente:
coluna IN (SELECT ... FROM tabela_temporária)
Após as alterações acima, a consulta da função IN torna-se uma subconsulta IN e a subconsulta é uma subconsulta não correlacionada.
 
Para subconsultas IN não correlacionadas, o otimizador MySQL fornece uma estratégia de materialização de semi-junção para processamento de otimização. A estratégia de materialização de semi-junção consiste em materializar os resultados da subconsulta em uma tabela temporária e depois juntá-los à aparência. Como mostrado abaixo:
 

1.png

 

A concatenação pode ser em duas ordens:

  • Varredura de materialização: Indica uma varredura completa da tabela materializada, desde a tabela materializada até a aparência.
  • Pesquisa de materialização: Indica que desde a aparência até a tabela materializada, você pode utilizar o construtor principal para pesquisar dados na tabela materializada.

Varredura física e química

  1. Execute a subconsulta, use o índice auto_distinct_key e desduplique os resultados ao mesmo tempo;
  2. Salve os resultados da etapa anterior na tabela temporária modelo 1;
  3. Obtenha uma linha de dados da tabela temporária e encontre a linha que atende às condições suplementares na aparência;
  4. Repita a etapa 3 até que o percurso da tabela temporária seja concluído.

Pesquisa materializada

  1. Execute a subconsulta primeiro;
  2. Salve os resultados obtidos na etapa anterior em uma tabela temporária;
  3. Pegue uma linha de dados da aparência, vá até a tabela temporária materializada para encontrar linhas que atendam às condições suplementares, use a chave primária da tabela materializada e verifique uma linha por vez;
  4. Repita 3 até ver todo o visual.

O otimizador escolhe diferentes ordens de concatenação dependendo do tamanho da aparência interna. Em cenários reais, a quantidade de dados nas tabelas geralmente consultadas é muito grande, dezenas de milhões ou mesmo centenas de milhões, o número de elementos na lista IN é muito menor que o número de tabelas, e o otimizador escolherá a Materialização; -scan método para varredura Se a chave primária for usada durante a aparência do índice de consulta, o número total de linhas verificadas após a otimização será N. Quando M for muito maior que N, a melhoria de desempenho será muito óbvia.

Instruções

O parâmetro rds_in_predicate_conversion_threshold é uma opção para modificar a função de consulta na parte inferior do predicado IN. Quando o número de elementos na lista de predicados IN da instrução SQL exceder o valor do parâmetro, a estratégia de otimização será iniciada. A função é usada através do valor desta variável. A seguir está um exemplo simples que ilustra o uso da otimização:

Estrutura da tabela

criar tabela t1(id int, a int, chave idx1(a));
Verifique as frases
selecione * de t1 onde a in (1,2,3,4,5);

Defina set rds_in_predicate_conversion_threshold = 0 e defina range_optimizer_max_mem_size=1 para desligar a função de otimização de predicado IN grande e a estratégia de otimização de varredura de intervalo. Verifique o plano de execução da instrução de consulta acima.

> definir rds_in_predicate_conversion_threshold = 0; > definir range_optimizer_max_mem_size=1; > explique select * from t1 onde a in (1,2,3,4,5);  
O resultado é o seguinte:
+----+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -+-------------+ | identificação | tipo_selecionado | mesa | divisórias | tipo | chaves_possíveis | chave | key_len | referência | linhas | filtrado | Extras | +----+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -+-------------+ | 1 | SIMPLES | t3 | NULO | TODOS | chave1 | NULO | NULO | NULO | 3 | 50,00 | Usando onde | +----+---------+-------+------------+------+-- -------------+------+---------+------+------+----- -++-------------+ 1 linha no conjunto, 2 avisos (0,00 seg)  
mostrar avisos; +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ | Nível | Código | Mensagem | +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ | Aviso | 3170 | Capacidade de memória de 1 byte para 'range_optimizer_max_mem_size' excedida. A otimização de intervalo não foi feita para esta consulta. | | Nota | 1003 | /* selecione#1 */ selecione `test`.`t3`.`id` AS `id`,`test`.`t3`.`a` AS `a` de `test`.`t3` onde (` teste`.`t3`.`a` em (3,4,5)) | +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ 2 linhas no conjunto (0,00 seg)

Verificou-se que um aviso foi relatado quando a instrução acima foi executada. As informações de aviso mostraram que, como a memória usada durante o processo de otimização de intervalo excedeu range_optimizer_max_mem_size, a otimização do limite de intervalo não foi usada para a instrução. Como resultado, o tipo de varredura muda para ALL e se torna uma varredura completa da tabela.

Defina set rds_in_predicate_conversion_threshold = 3 para ativar a opção de otimização de predicado IN grande, o que significa que quando os elementos da lista de predicados IN excederem 3, a estratégia de otimização de consulta de fila IN grande será ativada. Execute a instrução EXPLAIN FORMAT=TREE para ver se a otimização entra em vigor.

> definir rds_in_predicate_conversion_threshold = 3; > explicar formato=árvore selecione * de t1 onde a in (1,2,3,4,5); +---------------------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ | EXPLICAR | +---------------------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ | -> Junção interna de loop aninhado (custo = 0,70 linhas = 1) -> Filtro: (t1.a não é nulo) (custo = 0,35 linhas = 1) -> Verificação de tabela em t1 (custo = 0,35 linhas = 1) -> Pesquisa de índice de linha única em <in_predicate_2> usando <auto_distinct_key> (a=t1.a) (custo=0,35 linhas=1) | +---------------------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ 1 linha no conjunto (0,00 seg)

A tabela <in_predicate_*> (* é um número) no plano de execução é uma tabela temporária construída no Big INTool, que armazena todos os dados na lista de predicados IN.

Restrições de uso

As instruções de consulta suportadas pela otimização Big IN incluem a seguinte lista de instruções:

  • escolher
  • Inserir...selecionar
  • substituir...selecionar
  • ponto de vista de apoio
  • STMT preparado

Restrições e Limitações

A consulta do rotor Big IN usa a solução de otimização de subconsulta fornecida pelo mysql para obter desempenho. Portanto, existem as seguintes restrições de uso, caso contrário, reduzirá o desempenho.

  • Cenários onde a indexação não pode ser usada não são suportados
  • Suporta apenas constante IN LIST (incluindo NOW(), ? e outras instruções que não envolvem consultas de tabela)
  • Procedimentos/funções/gatilhos armazenados não são suportados
  • Não suportado ou ausente

Comparação de teste de cenário típico

A estrutura do teste da tabela é a seguinte:

CREATE TABLE `sbtest1` ( `id` int NOT NULL AUTO_INCREMENT, `k` int NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '' , CHAVE PRIMÁRIA (`id`), CHAVE `k_1` (`k`) ) ENGINE=InnoDB;  
O volume de dados da tabela é 1000w.
> selecione contagem(*) de sbtest1; +----------+ | contagem(*) | +----------+ | 10000000 | +----------+

A instrução de consulta é a seguinte, na qual o campo de condição é indexado e a lista IN contém 10.000 números constantes.

selecione contagem (*) de sbtest1 onde k em (2708275,5580784,7626186,8747250,228703,4589267,5938459,6982345,2665948,4830545,4929382,8723757,354179,1903 875,5111120,5471341,7098051,3113388,2584956,6550102 ,2842606,2744112,7077924,4580644,5515358,1787655,6391388,6044316,2658197,5628504,413887,6058866,3321587,1430333,445303,73 73496,9133196,6760595,4735642,4756387,9845147,9362192,7271805,4351748,6625915 ,3813276,4236692,8308973,4407131,9481423,3301846,432577,810938,3830320,6120078,6765157,6456566,6649509,1123840,2906490,99 65014.3725748,...);

A comparação de desempenho é mostrada na figura abaixo:

2.png

Pode-se observar que após a otimização na lista, o desempenho melhorou 36 vezes em comparação com o método original.

Clique para seguir e conhecer as novas tecnologias da Huawei Cloud o mais rápido possível~

 

Estudantes do ensino médio criam sua própria linguagem de programação de código aberto como uma cerimônia de maioridade - comentários contundentes de internautas: Contando com a defesa, a Apple lançou o chip M4 RustDesk Os serviços domésticos foram suspensos devido a fraude desenfreada. No futuro, ele planeja produzir um jogo independente na plataforma Windows Taobao (taobao.com) Reiniciar o trabalho de otimização da versão web, destino dos programadores, Visual Studio Code 1.89 lança Java 17, a versão Java LTS mais comumente usada, Windows 10 tem um participação de mercado de 70%, o Windows 11 continua diminuindo Open Source Daily | Google apoia Hongmeng para assumir o controle do Rabbit R1 de código aberto; a ansiedade e as ambições da Microsoft encerraram a plataforma aberta;
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/4526289/blog/11105468
Recomendado
Clasificación