Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como posso evitar uma verificação completa da tabela nesta consulta mysql?


Com base no EXPLAIN output em sua pergunta, você já tem todos os índices que a consulta deveria estar usando, a saber:
CREATE INDEX idx_zip_from_distance
  ON zipcode_distances (zipcode_from, distance, zipcode_to);
CREATE INDEX idx_zipcode ON venues (zipcode, id);
CREATE INDEX idx_venue_id ON events (venue_id);

(Não tenho certeza de seus nomes de índice se idx_zip_from_distance realmente inclui o zipcode_to coluna. Caso contrário, você deve adicioná-lo para torná-lo um índice de cobertura . Além disso, incluí o venues.id coluna em idx_zipcode para completar, mas, supondo que seja a chave primária da tabela e que você esteja usando o InnoDB, ela será incluída automaticamente de qualquer maneira.)

No entanto, parece que o MySQL está escolhendo um plano de consulta diferente e possivelmente abaixo do ideal, onde ele verifica todos os eventos, encontra seus locais e códigos postais e só então filtra os resultados por distância. Isso poderia ser o plano de consulta ideal, se a cardinalidade da tabela de eventos for baixa o suficiente, mas pelo fato de você estar fazendo essa pergunta, suponho que não seja.

Um motivo para o plano de consulta abaixo do ideal poderia seja o fato de você ter muitos índices que confundem o planejador. Por exemplo, você realmente precisa de todos esses três índices na tabela de CEP, já que os dados armazenados são presumivelmente simétricos? Pessoalmente, sugiro apenas o índice que descrevi acima, além de um índice exclusivo (que também pode ser a chave primária, se você não tiver uma artificial) em (zipcode_to, zipcode_from) (de preferência nessa ordem, para que quaisquer consultas ocasionais em zipcode_to=? pode fazer uso).

No entanto, com base em alguns testes que fiz, suspeito que o principal problema pelo qual o MySQL está escolhendo o plano de consulta errado se resume simplesmente às cardinalidades relativas de suas tabelas. Presumivelmente, suas zipcode_distances reais a mesa é enorme , e o MySQL não é inteligente o suficiente para perceber o quanto as condições no WHERE cláusula realmente reduzi-lo.

Nesse caso, a melhor e mais simples correção pode ser simplesmente forçar MySQL para usar os índices que você deseja :
select
    *
from
    zipcode_distances z 
    FORCE INDEX (idx_zip_from_distance)
inner join
    venues v    
    FORCE INDEX (idx_zipcode)
    on z.zipcode_to=v.zipcode
inner join
    events e
    FORCE INDEX (idx_venue_id)
    on v.id=e.venue_id
where
    z.zipcode_from='92108' and
    z.distance <= 5

Com essa consulta, você deve obter o plano de consulta desejado. (Você precisa de FORCE INDEX aqui, pois com apenas USE INDEX o planejador de consulta ainda pode decidir usar uma varredura de tabela em vez do índice sugerido, anulando o propósito. Isso aconteceu quando testei isso pela primeira vez.)

Ps. Aqui está uma demonstração do SQLize, tanto com e sem FORCE INDEX , demonstrando o problema.