Как улучшить этот запрос MySQL с помощью соединения?

У меня есть простой запрос, и он занимает более 14 секунд.

select 
     e.title, e.date, v.name, v.city, v.region, v.country

from seminar e force index for join (venueid) 
     left join venues v on e.venueid = v.id 

where v.country = 'US'
     and v.city = 'New York' 
     and v.region = 'NY'
     and e.date > curdate() 
     and e.someid != 0

Примечание. count(e.id) – сокращение, используемое в целях отладки. Фактически мы получаем информацию из обеих таблиц.

Объяснить дает это:

+----+-------------+-------+-------------+--------------------------------------------------------------------------------------+--------------------------+---------+-----------------+------+--------------------------------------------------------+
| id | select_type | table | type        | possible_keys                                                                        | key                      | key_len | ref             | rows | Extra                                                  |
+----+-------------+-------+-------------+--------------------------------------------------------------------------------------+--------------------------+---------+-----------------+------+--------------------------------------------------------+
|  1 | SIMPLE      | v     | index_merge | PRIMARY,city,country,region | city,region | 378,378 | NULL            |    2 | Using intersect(city,region); Using where |
|  1 | SIMPLE      | e     | ref         | venueid                     |  venueid    | 5       | v.id            |   11 | Using where                                            |
+----+-------------+-------+-------------+--------------------------------------------------------------------------------------+--------------------------+---------+-----------------+------+--------------------------------------------------------+

У меня есть индексы по e.id, e.date, e.someid, а также v.id, v.country, v.city и v.region.

Я знаю, что настройка db - это беспорядок, но это то, с чем мне приходится иметь дело прямо сейчас.

Почему SQL занимает так много времени, в конце концов будет ок. считать 150? На мероприятиях около 1 млн записей, а на площадках около 100 тыс.

Обе таблицы MyISAM. Есть идеи, как это улучшить?

При создании такого индекса

create index location on venues (city, region, country)

это занимает 20 секунд, объяснение таково:

+----+-------------+-------+------+--------------------------------------+--------------+---------+-------------------+------+------------------------------------+
| id | select_type | table | type | possible_keys                        | key          | key_len | ref               | rows | Extra                              |
+----+-------------+-------+------+--------------------------------------+--------------+---------+-------------------+------+------------------------------------+
|  1 | SIMPLE      | v     | ref  | PRIMARY,city,country,region,location | location     | 765     | const,const,const |  410 | Using index condition; Using where |
|  1 | SIMPLE      | e     | ref  | EventVenueID                         | venueid      | 5       | v.id              |   11 | Using where                        |
+----+-------------+-------+------+--------------------------------------+--------------+---------+-------------------+------+------------------------------------+

person hogan    schedule 01.07.2015    source источник
comment
Вам нужно количество мероприятий, которые проходят в Ванкувере?   -  person Bohemian♦    schedule 01.07.2015
comment
На самом деле мне нужна информация из таблиц, счетчик - это просто аббревиатура, чтобы ограничить вывод, когда я пытаюсь оптимизировать запрос.   -  person hogan    schedule 01.07.2015
comment
Затем вы должны отредактировать свой запрос, чтобы показать пару столбцов - это меняет вопрос.   -  person Bohemian♦    schedule 01.07.2015


Ответы (3)


У вас есть left join venues, но у вас есть условия в предложении where для присоединенной строки venues, поэтому будут возвращены только присоединенные строки. Однако это побочный вопрос — читайте дальше, почему вам вообще не нужно соединение.

Далее, если указан город vancouver, нет необходимости также проверять страну или штат.

Наконец, если вы пытаетесь найти «сколько будущих событий в Ванкувере», вам не нужно присоединение, так как идентификатор места проведения является константой!

Попробуй это:

select count(*) as event_count
from events
where venueid = (select id from venues where city = 'vancouver')
and startdate > curdate() 
and te_id != 0

Mysql будет использовать индекс venueid без необходимости использовать подсказку. Если это не так, выполните это:

analyze events

который будет обновлять статистику распределения данных в проиндексированных столбцах. Обратите внимание: если многие ваши мероприятия проходят в Ванкувере, более эффективно не использовать индекс (поскольку к большинству строк все равно придется обращаться).

person Bohemian♦    schedule 01.07.2015
comment
Хорошая идея, здесь не сработает, потому что мне нужна информация по обеим таблицам. Я использовал count здесь, чтобы получить минимальный sql, на самом деле я получаю несколько столбцов. Город... не статичен, а определяется кодом здесь, на бэкенде, это могут быть и другие... или Ванкувер в США. - person hogan; 01.07.2015

Это сделает первую часть запроса быстрее:

INDEX(city, region, country)
person Rick James    schedule 01.07.2015
comment
Интересно, теперь это занимает 20 секунд. может быть, я вас неправильно понял, можете ли вы предоставить полное заявление? я использовал создание индекса местоположения на площадках (город, регион, страна) - person hogan; 01.07.2015
comment
Что такое `ОБЪЯСНИТЬ? Кэш был теплым? - person Rick James; 01.07.2015
comment
Я обновил вопрос. Что вы подразумеваете под теплым кешем? - person hogan; 01.07.2015
comment
Хм... Это озадачивает. Укажите SHOW CREATE TABLE для обеих таблиц; Мне нужно увидеть индексы. - person Rick James; 01.07.2015
comment
При первом запуске запроса кэш может быть холодным, и запрос должен извлекать данные с диска. Во второй раз кеш теплый, и запрос (часто) выполняется в десять раз быстрее. Если второй запрос занимает ‹2 мс, возможно, сработал кеш запросов; это чтение является поддельным. - person Rick James; 01.07.2015
comment
Есть ли около 410 строк в venues для Ванкувера? (Это кажется «неправильным».) - person Rick James; 01.07.2015
comment
Первый раз долго, потом быстро. Я специально очищаю кеш, чтобы посмотреть, как я могу улучшить запрос. Пользователи ищут события в разных местах, и поэтому места разные. Тогда запрос будет в основном работать медленно для этих сценариев. У вас есть альтернативное решение для этого? - person hogan; 01.07.2015
comment
Я использую этот метод для получения показателя «стоимости» запроса: FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';. Большие числа = большая «стоимость». Часто встречаются числа, которые выглядят как количество строк в таблице — это, вероятно, указывает на сканирование таблицы. Пишет (в SELECT) указывает на таблицу tmp. И т. д. - person Rick James; 02.07.2015
comment
Как очистить кеш? Перезапустив mysqld? Даже если ваш кеш недостаточно велик, это излишне, потому что он сбрасывает блоки верхнего уровня в BTrees, что приводит к нереально высоким таймингам. Если, с другой стороны, вы имеете в виду кэш запросов, то просто выполните SELECT SQL_NO_CACHE ... при тестировании. - person Rick James; 02.07.2015
comment
Я использую RamMap от Sysinternals и очищаю резервный список. Система работает на машине Windows. - person hogan; 02.07.2015
comment
Если вы используете Engine=MyISAM, это (я думаю) уничтожает только блоки данных; блоки индекса кэшируются в key_buffer. Если вы используете Engine=InnoDB, это (я думаю) ничего не делает для MySQL. Не используйте его; это только запутывает проблему. - person Rick James; 02.07.2015
comment
Обе таблицы MyISAM. - person hogan; 02.07.2015

Я пошел другим путем, поскольку кажется, что MySQL не может эффективно обрабатывать соединения:

  • Создал одну большую новую таблицу со всеми столбцами, которые мне нужны из объединения.
  • Итак, семинары и мероприятия теперь в одном столе
  • добавлены индексы

Теперь запрос быстрый. Не знаю, почему...

С 25 секунд мы сократились до 0,08 секунды.

Вот как я этого хотел.

Если кто-то все еще знает, почему, вы более чем можете дать ответ.

person hogan    schedule 08.07.2015