Оптимизация сложного запроса

isqad

isqad88
Здравствуйте!

Существуют две таблицы: tenders и organizations. У конкурсов (tenders) есть участники (берутся из organizations (далее компаний)), подрядчики (тоже из компаний), заказчики (из компаний), победитель (компания). Связи между участниками и конкурсами при этом - многие ко многим, подрядчиками и конкурсами - многие к одному (так же и с заказчиками и победителем). Соответственно, получается большой запрос с join если необходимо выбрать конкурсы со всеми сразу:

PHP:
SELECT t, customers, contractors, party, winner FROM tenders t LEFT JOIN t.organizations customers LEFT JOIN t.contractors contractors LEFT JOIN t.party party LEFT JOIN t.winner winner ... (в настоящем проекте еще 3-5 join-ов)
При этом, должна быть еще постраничная навигация (добавляются LIMIT и OFFSET)
Понятно, что стоит этот запрос разбить хотя бы на 2 запроса, так как запрос выше выполняется ну очень медленно, но как это сделать с LIMIT и OFFSET?

Индексы расставлены на полях, по которым происходит чаще всего сортировка и выборка с условием.

Вот запрос из реального приложения, как видите, куча join-ов, по-другому никак, и этот запрос тормозит:

PHP:
SELECT t, o, p, c, w, m, f, parent, cparent, com, party FROM PortalTenderBundle:Tender t
                         LEFT JOIN t.organization o
                         LEFT JOIN o.parent parent
                         LEFT JOIN t.provision p
                         LEFT JOIN t.contractors c
                         LEFT JOIN c.parent cparent
                         LEFT JOIN t.contractors cf
                         LEFT JOIN t.winner w
                         LEFT JOIN t.manager m
                         LEFT JOIN t.files f
                         LEFT JOIN t.comments com
                         LEFT JOIN t.party party
                         LEFT JOIN t.party party_f
                         WHERE ((t.opening_at IS NULL) OR (t.opening_at IS NOT NULL AND t.opening_at <= CURRENT_TIMESTAMP()))
В догонку вот еще вопрос: получится ли повысить производительность запроса, если часть связующих таблиц поместить в redis?
 

С.

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

Очень трудно вникать в запрос с однобуквенными алисами, но создается впечатление, что 3/4 JOIN'ов там просто излишни. Даже просто потому что на 11 колонок SELECT'a в принципе не может понадобиться 12 JOIN'ов.
 

Фанат

oncle terrible
Команда форума
тормозящий запрос следует прогонять через EXPLAIN
 

SiZE

Новичок
Где explain ? Где стоимость запросов или время работы запроса? Зачем оптимизировать запрос?
 

isqad

isqad88
Работают) 102ms на продакшн. Лишних join нет, это для фильтров. Через explain пробовал, сразу результаты не могу выслать, так как в транспорте. Но могу сказать что больше всего времени уходит на send data. Индексы вроде проставлены верно, explian опубликую позже.
 

isqad

isqad88
Запрос оптимизировать для увеличения скорости работы приложения, добавлю что я привел пример doctrine query language запроса, работаю с symfony 2 framework. Так что это не поля в запросе а объекты.
 

isqad

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

Очень трудно вникать в запрос с однобуквенными алисами, но создается впечатление, что 3/4 JOIN'ов там просто излишни. Даже просто потому что на 11 колонок SELECT'a в принципе не может понадобиться 12 JOIN'ов.
То есть вы считаете выполнять несколько запросов лучше чем один, а результаты собирать в самом приложении? Если так, то я даже рад буду )
 

Фанат

oncle terrible
Команда форума
хм. это mysql?
send data, вроде бы, show profiles показывает, а не эксплейн?
 

С.

Продвинутый новичок
То есть вы считаете выполнять несколько запросов лучше чем один, а результаты собирать в самом приложении?
Одним запросом или несколькоми, не в этом дело. Я хочу сказать, что JOINы надо делать только там, где они нужны. Между двумя объектами в базе может быть логическая связь. Но если в данном конкретном запросе меня эта связь не интересует, то на кой хрен ее проJOINивать? JOINи, что тебе реально надо, а не все, что в принципе можно. Крайне редко, если вообще когда-либо нужна вся сеть логических связей приложения за один раз.
 

isqad

isqad88
Одним запросом или несколькоми, не в этом дело. Я хочу сказать, что JOINы надо делать только там, где они нужны. Между двумя объектами в базе может быть логическая связь. Но если в данном конкретном запросе меня эта связь не интересует, то на кой хрен ее проJOINивать? JOINи, что тебе реально надо, а не все, что в принципе можно. Крайне редко, если вообще когда-либо нужна вся сеть логических связей приложения за один раз.
В том-то и дело, что все эти joinы нужны, чтобы сразу все выводить на страницу. И подрядчиков и заказчиков и участников и файлы, и т.д. для каждого конкурса, а конкурсов выводить надо по 100 штук на страницу, я и спрашиваю вас как это лучше делать. Сам-то я прекрасно знаю, что по-хорошему так никто не делает, но вот понадобилось.
 

С.

Продвинутый новичок
Не верю! Хочется посмотреть на макет этой страницы со списком, где в каждой строке все-все-все.
 

С.

Продвинутый новичок
Ну что ж, крутая таблица. Только я все равно не понимаю смысл джойнов таблицы тендеров с самой собой по многу раз. Например можешь объяснить смысл:
PHP:
LEFT JOIN t.comments com
 
Сверху