Mysql
 sql >> база данни >  >> RDS >> Mysql

Как мога да избегна пълно сканиране на таблицата на тази mysql заявка?

Въз основа на EXPLAIN изход във вашия въпрос, вече имате всички индекси, които заявката трябва да използвате, а именно:

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);

(Не съм сигурен от имената на вашия индекс дали idx_zip_from_distance наистина включва zipcode_to колона. Ако не, трябва да го добавите, за да го направите покриващ индекс . Освен това включих venues.id колона в idx_zipcode за пълнота, но ако приемем, че това е първичният ключ за таблицата и че използвате InnoDB, той така или иначе ще бъде включен автоматично.)

Изглежда обаче, че MySQL избира различен и вероятно неоптимален план за заявка, където сканира всички събития, намира техните места и пощенски кодове и едва след това филтрира резултатите по разстояние. Това може бъде оптималният план за заявка, ако мощността на таблицата със събития е била достатъчно ниска, но от факта, че задавате този въпрос, предполагам, че не е така.

Една от причините за неоптималния план за заявка може бъде фактът, че имате твърде много индекси, които объркват плановицата. Например, наистина ли имате нужда и от трите индекса в таблицата с пощенски кодове, като се има предвид, че данните, които съхранява, вероятно са симетрични? Лично аз бих предложил само индекса, който описах по-горе, плюс уникален индекс (който може да бъде и първичен ключ, ако нямате изкуствен) на (zipcode_to, zipcode_from) (за предпочитане в този ред, така че всякакви случайни заявки към zipcode_to=? може да се възползва от него).

Въпреки това, въз основа на някои тестове, които направих, подозирам, че основният проблем, поради който MySQL избира грешен план за заявка, се свежда просто до относителните характеристики на вашите таблици. Вероятно вашите действителни zipcode_distances масата е огромна , а MySQL не е достатъчно умен, за да разбере колко много са условията в WHERE клаузата наистина го стеснява.

Ако е така, най-доброто и просто решение може да бъде просто принудително MySQL, за да използвате индексите, които искате :

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

С тази заявка наистина трябва да получите желания план за заявка. (Необходим ви е FORCE INDEX тук, тъй като само с USE INDEX плановникът на заявки все пак може да реши да използва сканиране на таблица вместо предложения индекс, побеждавайки целта. Това ми се случи, когато за първи път тествах това.)

Пс. Ето демонстрация на SQLize, и двете с и без FORCE INDEX , демонстрирайки проблема.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Съхранение на излишни външни ключове, за да се избегнат присъединявания

  2. MySQL Изберете горните N реда

  3. Еквивалент на Laravel-5 „Харесвам“ (Eloquent)

  4. Как да игнорирате дублиращи се редове при вмъкване

  5. Връщане на DISTINCT първи знак на поле (MySQL)