Simples e fácil de entender, sobre o processo de execução e otimização do Group by

prefácio

Olá a todos, sou um garotinho que apanha caracóis .

No desenvolvimento diário, muitas vezes usamos group by. Caros amigos, vocês sabem como funciona o group by? Qual é a diferença entre agrupar por e ter? Qual é a ideia de otimização do group by? Quais são os problemas que precisam ser observados ao usar o group by? Este artigo aprenderá com você e conquistará o grupo ~

  • Exemplo simples usando group by
  • Como o agrupamento por funciona
  • A diferença entre agrupar por + onde e agrupar por + ter
  • agrupar por ideias de otimização
  • Notas sobre o uso de agrupar por
  • Como otimizar um SQL lento de produção

1. Exemplo simples usando agrupar por

Agrupar por é geralmente usado para agrupar estatísticas , e a lógica que expressa é agrupar de acordo com certas regras. Vamos começar com um exemplo simples e revisá-lo juntos.

Suponha que uma tabela de funcionários seja usada e a estrutura da tabela seja a seguinte:

CREATE TABLE `staff` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `id_card` varchar(20) NOT NULL COMMENT '身份证号码',
  `name` varchar(64) NOT NULL COMMENT '姓名',
  `age` int(4) NOT NULL COMMENT '年龄',
  `city` varchar(64) NOT NULL COMMENT '城市',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='员工表';
复制代码

Os dados de inventário da tabela são os seguintes:

Agora temos esse requisito: contar o número de funcionários em cada cidade . A instrução SQL correspondente pode ser escrita da seguinte forma:

select city ,count(*) as num from staff group by city;
复制代码

O resultado da execução é o seguinte:

A lógica dessa instrução SQL é muito clara, mas qual é o fluxo de execução subjacente?

2. Análise de grupo por princípio

2.1 explicar a análise

Vamos primeiro usar a explicação para visualizar o plano de execução

explain select city ,count(*) as num from staff group by city;
复制代码

  • O campo Utilizando temporário do Extra indica que a tabela temporária é utilizada quando o agrupamento é realizado.
  • O Using filesort do campo Extra indica que a classificação é usada

Como o group by usa tabelas temporárias e classificação? Vamos dar uma olhada no fluxo de execução deste SQL

2.2 Processo de execução simples de agrupamento por

explain select city ,count(*) as num from staff group by city;
复制代码

Vamos dar uma olhada no processo de execução deste SQL.

  1. Crie uma tabela temporária de memória com dois campos cidade e num;
  2. A tabela completa varre os registros da equipe e recupera sequencialmente os registros com cidade = 'X'.
  • Determine se existe uma linha com city='X' na tabela temporária , caso não exista, insira um registro (X,1);
  • Se houver uma linha com city='X' na tabela temporária, adicione 1 ao valor num da linha de x;
  1. Após a conclusão da travessia, classifique de acordo com a cidade do campo para obter o conjunto de resultados e devolvê-lo ao cliente.

O diagrama de execução deste processo é o seguinte:

Qual é a ordenação da tabela temporária?

É colocar os campos que precisam ser ordenados no buffer de ordenação, e retornar após a ordenação. Preste atenção aqui, a classificação é dividida em classificação de campo completo e classificação de rowid

Se for uma classificação de campo completa, os campos que precisam ser consultados e retornados são colocados no buffer de classificação e são classificados de acordo com os campos de classificação e são retornados diretamente . . Como determinar se deve ser usada a classificação de campo completo ou a classificação de rowid? Controlado por um parâmetro de banco de dados, max_length_for_sort_data

Para aqueles que estão interessados ​​em aprender mais sobre classificação, podem ler meu artigo.

  • Leia uma vez para entender: ordene por explicação detalhada

3. A diferença entre onde e ter

  • Processo de execução do agrupamento por + onde
  • Processo de execução do grupo por + ter
  • Ao mesmo tempo, há a ordem de execução de onde, agrupar por e ter

3.1 Processo de execução do agrupamento por + onde

Alguns amigos acham que o SQL da seção anterior é muito simples.Se a condição where é adicionada, e a coluna onde condição é indexada, qual é o processo de execução ?

Ok, vamos adicionar uma condição a ele e adicionar um índice de idx_age, da seguinte forma:

select city ,count(*) as num from staff where age> 30 group by city;
//加索引
alter table staff add index idx_age (age);
复制代码

Vamos analisar novamente:

explain select city ,count(*) as num from staff where age> 30 group by city;
复制代码

A partir dos resultados do plano de execução de explicação, pode-se descobrir que a condição de consulta atinge o índice de idx_age e usa tabelas temporárias e classificação

Usando condição de índice : Indica que o índice é pressionado para otimizar, filtrar os dados o máximo possível de acordo com o índice e, em seguida, retorná-los à camada do servidor para filtrar de acordo com outras condições. Por que há um pushdown de índice para um único índice aqui? A aparência de explicação não significa necessariamente que o pushdown do índice é usado, apenas significa que ele pode ser usado, mas não é necessariamente usado. Se você tiver alguma ideia ou dúvida, pode me adicionar no WeChat para discutir.

O fluxo de execução é o seguinte:

  1. Crie uma tabela temporária de memória com dois campos cidade e num;
  2. Examine a árvore de índice idx_age para encontrar o ID da chave primária cuja idade é maior que 30
  3. Através do ID da chave primária, volte para a tabela para encontrar cidade = 'X'
  • Determine se existe uma linha com city='X' na tabela temporária , caso não exista, insira um registro (X,1);
  • Se houver uma linha com city='X' na tabela temporária, adicione 1 ao valor num da linha de x;
  1. Continue a repetir as etapas 2 e 3 para encontrar todos os dados que atendem às condições,
  2. Por fim, classifique de acordo com o campo city , obtenha o conjunto de resultados e devolva-o ao cliente.

3.2 Execução do grupo por + tendo

Se você deseja consultar o número de funcionários em cada cidade e obter as cidades onde o número de funcionários não é inferior a 3, ter pode resolver muito bem seu problema. SQL Jiangzi escreveu:

select city ,count(*) as num from staff  group by city having num >= 3;
复制代码

Os resultados da consulta são os seguintes:

ter é chamado de condição de filtro de agrupamento, que opera no conjunto de resultados retornado.

3.3 Ordem de execução de onde, agrupar e ter ao mesmo tempo

Se um SQL contém where, group by e tendo cláusulas ao mesmo tempo, qual é a ordem de execução?

Por exemplo este SQL:

select city ,count(*) as num from staff  where age> 19 group by city having num >= 3;
复制代码
  1. Execute a cláusula where para encontrar dados de funcionários cuja idade seja maior que 19
  2. agrupar por cláusula nos dados dos funcionários, agrupados por cidade.
  3. Para os grupos de cidades formados pela cláusula group by, execute a função agregada para calcular o número de funcionários em cada grupo;
  4. Por fim, use a cláusula havendo para selecionar o grupo de cidades com o número de funcionários maior ou igual a 3.

3.4 onde + tendo resumo de diferenças

  • A cláusula having é usada para filtrar após o agrupamento e a cláusula where é usada para filtragem de condição de linha
  • Tendo geralmente aparece com agrupar por e funções de agregação como (count(), sum(), avg(), max(), min())
  • As funções agregadas não podem ser usadas na cláusula where condition, mas a cláusula having pode.
  • tendo só pode ser usado após group by, onde é executado antes de group by

4. Problemas com o grupo por

Os principais pontos a serem observados ao usar group by são:

  • O group by deve ser usado com funções agregadas?
  • O campo de agrupar por deve aparecer no select
  • Problema de SQL lento causado por group by

4.1 O agrupamento por deve ser usado com funções agregadas?

group por meio de estatísticas de agrupamento Geralmente, é usado com funções agregadas como (count(), sum(), avg(), max(), min()).

  • número de contagem
  • soma() soma
  • média() média
  • max() valor máximo
  • min() valor mínimo

Pode ser usado sem uma função agregada?

Estou usando o Mysql 5.7 e está ok. Nenhum erro será relatado, e o que é retornado é a primeira linha de dados do grupo.

Por exemplo este SQL:

select city,id_card,age from staff group by  city;
复制代码

O resultado da consulta é

Vamos comparar, o que é retornado são os primeiros dados de cada grupo

Claro, quando você costuma usá-lo, group by ainda é usado em conjunto com funções de agregação, a menos que haja alguns cenários especiais, como você deseja remover duplicatas, claro, também é possível reutilizar distintos.

4.2 Os campos seguidos de agrupar por devem aparecer no select.

Não necessariamente, como o seguinte SQL:

select max(age)  from staff group by city;
复制代码

O resultado da execução é o seguinte:

A cidade do campo de agrupamento não está atrás da seleção e não relatará um erro. Claro, isso pode estar relacionado a diferentes bancos de dados e versões diferentes . Ao usá-lo, você pode verificá-lo primeiro. Há um ditado que diz que o que você recebe no papel será superficial e você nunca saberá o que fazer .

4.3 Problemas de SQL lentos causados ​​por group by

Para o ponto de atenção mais importante, o uso indevido de group by pode facilmente causar problemas de SQL lento. Porque ele usa tabelas temporárias e classificação por padrão . Às vezes , tabelas temporárias de disco também podem ser usadas .

Se o tamanho da tabela temporária de memória atingir o limite superior durante o processo de execução (o parâmetro que controla esse limite superior é tmp_table_size), a tabela temporária de memória será convertida em uma tabela temporária de disco . Se a quantidade de dados for grande, é provável que a tabela temporária de disco exigida por esta consulta ocupe muito espaço em disco.

Esses são todos os fatores X que levam ao SQL lento. Vamos discutir soluções de otimização juntos.

5. Alguns esquemas de otimização de agrupamento por

Em que direção otimizar?

  • Direção 1: Como será classificado por padrão, não vamos classificá-lo.
  • Direção 2: Como a tabela temporária é o fator X que afeta o desempenho do group by, não podemos usar a tabela temporária?

Vamos pensar juntos, por que você precisa de uma tabela temporária para executar um grupo por instrução? A lógica semântica do group by é contar o número de ocorrências de valores diferentes. Se esses valores estiverem em ordem desde o início , podemos apenas digitalizar as estatísticas diretamente, em vez de usar uma tabela temporária para registrar e contar os resultados ?

  • O campo depois de agrupar por é indexado
  • ordenar por nulo sem ordenar
  • Tente usar apenas tabelas temporárias na memória
  • Usar SQL_BIG_RESULT

5.1 Adicionar índice ao campo após agrupar por

Como garantir que os valores dos campos após agrupar por estejam em ordem desde o início? Claro que é indexação .

Vamos voltar a este SQL

select city ,count(*) as num from staff where age= 19 group by city;
复制代码

seu plano de execução

Se adicionarmos um índice conjunto a ele idx_age_city (idade, cidade)

alter table staff add index idx_age_city(age,city);
复制代码

Olhando novamente para o plano de execução, descobri que nem a classificação nem as tabelas temporárias são necessárias.

Adicionar um índice adequado é a maneira mais fácil e eficaz de otimizar o agrupamento.

5.2 ordenar por nulo sem ordenar

Nem todos os cenários são adequados para indexação. Se encontrarmos um cenário que não seja adequado para a criação de um índice, como podemos otimizá-lo?

Se suas necessidades não exigirem a classificação do conjunto de resultados, você poderá usar order by null.

select city ,count(*) as num from staff group by city order by null
复制代码

O plano de execução é o seguinte, não há mais classificação de arquivos

5.3 Tente usar apenas tabelas temporárias na memória

Se não houver muitos dados para serem contados por group by, podemos tentar usar apenas tabelas temporárias de memória o máximo possível ; porque se o processo de group by não caber nos dados, é demorado usar tabelas temporárias de disco. Portanto, o parâmetro tmp_table_size pode ser aumentado adequadamente para evitar o uso de tabelas temporárias de disco .

5.4 Otimizando com SQL_BIG_RESULT

E se a quantidade de dados for muito grande? Não é possível aumentar tmp_table_size infinitamente? Mas você não pode apenas observar os dados colocados na tabela temporária de memória primeiro e depois transformá-los em uma tabela temporária de disco quando a inserção de dados descobrir que o limite superior foi atingido? Isso é um pouco sem inteligência.

Portanto, se o volume de dados estimado for relativamente grande, usamos a dica SQL_BIG_RESULT para usar diretamente a tabela temporária do disco. O otimizador MySQl descobriu que a tabela temporária do disco é armazenada em uma árvore B+ e a eficiência do armazenamento não é tão alta quanto a de um array. Portanto, ele será armazenado diretamente em uma matriz

Um exemplo de SQL é o seguinte:

select SQL_BIG_RESULT city ,count(*) as num from staff group by city;
复制代码

Como você pode ver no campo Extra do plano de execução, a execução não usa tabelas temporárias, mas apenas ordena

O fluxo de execução é o seguinte:

  1. Inicialize sort_buffer e coloque-o no campo cidade;
  2. Escaneie a pauta da mesa, tire os valores da cidade por sua vez e armazene-os em sort_buffer;
  3. Após a conclusão da verificação, classifique o campo cidade de sort_buffer
  4. Após a ordenação ser concluída, uma matriz ordenada é obtida.
  5. De acordo com uma matriz ordenada, conte o número de ocorrências de cada valor.

6. Como otimizar um SQL lento de produção

Recentemente encontrei uma produção SQL lenta, relacionada ao group by, deixe-me mostrar como otimizá-lo.

A estrutura da tabela é a seguinte:

CREATE TABLE `staff` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `id_card` varchar(20) NOT NULL COMMENT '身份证号码',
  `name` varchar(64) NOT NULL COMMENT '姓名',
  `status` varchar(64) NOT NULL COMMENT 'Y-已激活 I-初始化 D-已删除 R-审核中',
  `age` int(4) NOT NULL COMMENT '年龄',
  `city` varchar(64) NOT NULL COMMENT '城市',
  `enterprise_no` varchar(64) NOT NULL COMMENT '企业号',
  `legal_cert_no` varchar(64) NOT NULL COMMENT '法人号码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='员工表';
复制代码

O SQL para a consulta é este:

select * from t1 where status = #{status} group by #{legal_cert_no}
复制代码

Não vamos discutir se o = deste SQL é razoável. Se fosse um tal SQL, como você o otimizaria? Amigos que tenham ideias podem deixar uma mensagem para discutir, ou você pode me adicionar ao WeChat e discussões em grupo. Se você acha que o artigo está errado, você também pode trazê-lo à tona, vamos progredir juntos, vamos lá!

Acho que você gosta

Origin blog.csdn.net/wdjnb/article/details/124403974
Recomendado
Clasificación