2015-05-01 9 views
0

У меня есть две таблицы:MySQL: сохраненное вызов функции + левое соединение = очень очень медленно

module_339 (id,name,description,etc) 
module_339_schedule(id,itemid,datestart,dateend,timestart,timeend,days,recurrent) 

module_339_schedule.itemid указывает на module_339

кулак стол проводит конференции

второй один держит графики конференций

module_339 имеет 3 позиции

module_339_schedule имеет 4000+ элементов - почти поровну разделен между 3 конференциями

У меня есть хранимая функция - «getNextDate_module_339» - которая будет вычислять «следующую дату» для указанной конференции, для того, чтобы быть в состоянии отображать его, а также сортировать по нему - если пользователь хочет. Эта хранимая процедура будет просто принимать все записи расписания указанной конференции и прокручивать их, сравнивая даты и время. Таким образом, он сделает одно простое чтение из модуля_339_schedule, затем перебирает элементы и сравнивает даты и время.

Проблема: этот запрос очень медленно:

SELECT 
distinct(module_339.id) 
,min(getNextDate_module_339(module_339.id,1,false)) AS ND 
FROM 
module_339 
LEFT JOIN module_339_schedule on module_339.id=module_339_schedule.itemid /* standard schedule adding */ 
WHERE 1=1 AND module_339.is_system_preview<=0 
group by 
module_339.id 
order by 
module_339.id asc 

Если удалить либо вызов функции ИЛИ LEFT JOIN, это быстро снова. Что я здесь делаю неправильно? Кажется, это какой-то «столкновение» между вызовом функции и левым соединением.

ответ

1

Я думаю, что часть group by может быть удалена из этого запроса, что позволяет также удалить функцию min. Кроме того, нет большого количества WHERE 1=1 AND..., поэтому я тоже изменил это. Попробуйте это:

SELECT DISTINCT module_339.id 
       ,getNextDate_module_339(module_339.id,1,false) AS ND 
FROM module_339 
LEFT JOIN module_339_schedule ON module_339.id=module_339_schedule.itemid /* standard schedule adding */ 
WHERE module_339.is_system_preview<=0 
ORDER BY module_339.id 

Примечание, что это не может иметь много влияния на производительность.
Я думаю, что худшая часть производительности - это, вероятно, функция getNextDate_module_339.
Если вы можете найти способ получить его функциональность без использования функции в качестве вспомогательного запроса, ваш SQL-запрос, скорее всего, будет работать быстрее, чем сейчас, с или без левого соединения.
Если вам нужна помощь в этом, отредактируйте свой вопрос, чтобы включить функцию, и, надеюсь, я (или кто-то другой) мог бы помочь вам в этом.

+0

Это ускорит процесс, единственная проблема заключается в том, что этот запрос представляет собой упрощенную версию фактического запроса - это иллюстрирует ошибку - и автоматически генерируется, поэтому мне нужно будет проверить, не влияет ли это на что-либо еще в обработать. Тем не менее, ваш ответ фиксирует пунктуальный вопрос, который я задал. Поэтому я буду отмечать ваш ответ как решение. Спасибо! – Catalin

+0

Забыл сказать: хранимая функция довольно быстро сама по себе, именно в этой комбинации все становится болезненно медленным. – Catalin

+0

рад помочь :-) –

0

Из справочника MySQL:

Лучший способ повысить производительность операций SELECT, чтобы создать индексы на одной или нескольких колонок, которые проверены в запросе. Записи индекса действуют как указатели на строки таблицы, что позволяет быстро определить, какие строки соответствуют условию в предложении WHERE, и получить другие значения столбцов для этих строк. Все типы данных MySQL могут быть проиндексированы.

Хотя может возникнуть соблазн создать индексы для каждого столбца, используемого в запросе, ненужные индексы пространства для отходов и время отходов для MySQL, чтобы определить, какие индексы использовать. Индексы также добавляют к стоимости вставок, обновлений и удалений, потому что каждый индекс должен быть обновлен.Вы должны найти правильный баланс для достижения быстрых запросов с использованием оптимального набора индексов.

В качестве первого шага я предлагаю проверить, что объединенные столбцы индексированы. Поскольку первичные ключи всегда индексируются по умолчанию, мы можем предположить, что module_339 уже проиндексирован в столбце id, поэтому сначала проверьте, что module_339_schedule индексируется в столбце itemid. Вы можете проверить индексы на эту таблицу в MySQL с помощью:

SHOW INDEX FROM module_339_schedule; 

Если таблица не имеет индекс по этой колонке, вы можете добавить его с помощью:

CREATE INDEX itemid_index ON module_339_schedule (itemid); 

Это должно ускорить объединение компонент запроса.

Поскольку ваш запрос также ссылки module_339.is_system_preview вы можете также рассмотреть вопрос о добавлении индекса в эту колонку, используя:

CREATE INDEX is_system_preview_index ON module_339 (is_system_preview); 

Вы также мог бы быть в состоянии оптимизировать хранимую процедуру, но вы не включили его в ваш вопрос.

+0

индексы правильно созданы; сохраненная функция довольно быстро при вызове сама по себе – Catalin

+0

Вы также можете проверить, что наборы символов в вашей базе данных соответствуют наборам символов в ваших таблицах. См. Http://stackoverflow.com/a/16949603/4853273. – kaiyobi

Смежные вопросы