Ocorreu um problema estranho na consulta do módulo de pedido pelo qual meu colega era responsável há dois dias. Quando as condições do filtro forem adicionadas, o problema de tempo limite da consulta ocorrerá. Não há problema ao consultar todos os pedidos. O SQL é o seguinte (os dados foram dessensibilizados e o MySql é usado):
SELECT
a.consumer_code AS orderCode,
a.rent_equipment_snid AS eqSn,
a.powerbank_snid AS pbSn,
a.rent_merchant_name AS rentMerchant,
a.rent_merchant_address AS merchantAddress,
a.rent_date AS rentTime,
a.close_date AS returnTime,
a.payment_money AS orderAmount,
a.order_status AS orderStatus,
a.consume_schema AS consumeSchema,
a.transaction_status AS transStatus,
a.rent_equipment_model AS eqModel
FROM
cp_consumer_order_2020_10 a
WHERE
a.agent_code = xxxx
# 下面两个条件就是筛选时才会加上
AND a.order_status = xxx
AND a.close_date IS NULL
ORDER BY
a.consumer_code desc
cp_consumer_order_2020_10 é uma tabela de pedido mensal com quase 10 milhões de dados, consumer_code é a chave primária e agent_code tem um índice normal.
Eu executei o SQL acima no banco de dados e descobri que o índice agent_code havia sumido e a eficiência da consulta estava normal. Então, excluí as condições do filtro e os resultados da execução foram os mesmos.
O acima é um plano de execução condicional e incondicional, você pode ver que não há diferença. Neste momento, gostaria de saber se há alguma operação demorada no
código : este código não parece ter nenhuma operação particularmente demorada, getAgentOrderList é para executar esse SQL, getAgentStaffOrderList também tentou consultar muito rapidamente, por causa da paginação, o seguinte para A execução do loop não será particularmente lenta.
É possível que outro "incidente espiritual" tenha ocorrido? A essa altura, pensei subitamente se poderia ser causado por paginação.Todos sabemos que esse limite causará uma consulta lenta quando o deslocamento for muito grande, mas ainda não viramos a página, que é a primeira página, então esse não é o problema.
Além disso, eu pensei que já tinha visto o problema de erros de seleção de índice ao usar limite e ordem por antes.Por isso trouxe limit 0,30 e executei o SQL agora mesmo no banco de dados.Como esperado, apareceu SQL lento. Neste momento, vejo o plano de execução da seguinte maneira:
Você pode ver que o Mysql usa o índice de chave primária neste momento, ou seja, o campo que classificamos, então sugiro que meus colegas usem índice de força para forçar o índice normal, e a consulta retorna ao normal.
Neste ponto, a otimização SQL acabou, mas por que adicionar limite fará com que o Mysql selecione o índice errado e por que é tão lento usar o índice de chave primária e o número estimado de linhas verificadas é obviamente menor? Seguindo o princípio de “saber o que se passa, mas também saber porquê”, verifiquei muitas informações, mas não consegui resolver totalmente as dúvidas do meu coração, acabei por tentar várias vezes e por fim descobri.
- Em primeiro lugar, por que é mais rápido pegar índices normais e mais lento para índices de chave primária?
Como meu SQL é o resultado da consulta ao índice da chave primária na ordem reversa, o índice é naturalmente ordenado e não precisa ser classificado, então vejo que o campo Extra no plano de execução não tem o uso de arquivosort, que é mais rápido do que o índice comum, mas este SQL é filtrado pelas condições de onde Sim, depois de obter os resultados solicitados, você precisa retirar o agent_code e as condições, um por um, para corresponder. Vendo isso, acredito que os leitores devam basicamente entender. Se não houver limite, então esse SQL fará uma varredura completa da tabela; e houver um limite de 0,30, ocorrerá a seguinte situação: Primeiro, os 30 registros que correspondem à condição where estão corretos Se forem os primeiros 30 itens após a classificação, então o mysql só precisa verificar 30 itens; se houver menos de 30 itens ou os registros correspondentes estiverem no final da classificação, toda a tabela será verificada. No entanto, o índice normal agent_code não tem esse problema, porque a condição do filtro é agent_code, que pode ser correspondida rapidamente. - Por que o índice de chave primária é usado quando o limite é adicionado?
Porque se o índice de chave primária for usado sem limite, ele corresponderá à condição where, um por um, conforme mencionado acima, mas não há limite para o número de itens retornados, e uma verificação completa da tabela será realizada (você pode usar forçar índice (primário) + explicar para ver a linha É o número total de linhas na tabela (1000w), o Mysql pensa que é mais rápido usar índices comuns, porque o número estimado de linhas de varredura para índices comuns é menor que 1,8W; mas após adicionar o limite, o número estimado de linhas de varredura para o índice de chave primária pode ser É menor que o número estimado de linhas de varredura para índices normais, o que leva a erros de seleção de índice.