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

  • Автор темы Автор темы isqad
  • Дата начала Дата начала

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'ов.
 
Где explain ? Где стоимость запросов или время работы запроса? Зачем оптимизировать запрос?
 
Работают) 102ms на продакшн. Лишних join нет, это для фильтров. Через explain пробовал, сразу результаты не могу выслать, так как в транспорте. Но могу сказать что больше всего времени уходит на send data. Индексы вроде проставлены верно, explian опубликую позже.
 
Запрос оптимизировать для увеличения скорости работы приложения, добавлю что я привел пример doctrine query language запроса, работаю с symfony 2 framework. Так что это не поля в запросе а объекты.
 
Все описанные в первом абзаце связи имеют место быть в логике приложения в целом. Совсем не обязательно, чтобы они все были воплощены в один запрос. Выбирайте только то, что нужно в данном конкретном месте.

Очень трудно вникать в запрос с однобуквенными алисами, но создается впечатление, что 3/4 JOIN'ов там просто излишни. Даже просто потому что на 11 колонок SELECT'a в принципе не может понадобиться 12 JOIN'ов.
То есть вы считаете выполнять несколько запросов лучше чем один, а результаты собирать в самом приложении? Если так, то я даже рад буду )
 
хм. это mysql?
send data, вроде бы, show profiles показывает, а не эксплейн?
 
То есть вы считаете выполнять несколько запросов лучше чем один, а результаты собирать в самом приложении?
Одним запросом или несколькоми, не в этом дело. Я хочу сказать, что JOINы надо делать только там, где они нужны. Между двумя объектами в базе может быть логическая связь. Но если в данном конкретном запросе меня эта связь не интересует, то на кой хрен ее проJOINивать? JOINи, что тебе реально надо, а не все, что в принципе можно. Крайне редко, если вообще когда-либо нужна вся сеть логических связей приложения за один раз.
 
Одним запросом или несколькоми, не в этом дело. Я хочу сказать, что JOINы надо делать только там, где они нужны. Между двумя объектами в базе может быть логическая связь. Но если в данном конкретном запросе меня эта связь не интересует, то на кой хрен ее проJOINивать? JOINи, что тебе реально надо, а не все, что в принципе можно. Крайне редко, если вообще когда-либо нужна вся сеть логических связей приложения за один раз.
В том-то и дело, что все эти joinы нужны, чтобы сразу все выводить на страницу. И подрядчиков и заказчиков и участников и файлы, и т.д. для каждого конкурса, а конкурсов выводить надо по 100 штук на страницу, я и спрашиваю вас как это лучше делать. Сам-то я прекрасно знаю, что по-хорошему так никто не делает, но вот понадобилось.
 
Не верю! Хочется посмотреть на макет этой страницы со списком, где в каждой строке все-все-все.
 
Ну что ж, крутая таблица. Только я все равно не понимаю смысл джойнов таблицы тендеров с самой собой по многу раз. Например можешь объяснить смысл:
PHP:
LEFT JOIN t.comments com
 
Сверху