Задать вопрос
yesworld
@yesworld

Как оптимизировать вложенные запрос mysql?

Всем привет.

Я пытаюсь разгрузить один запрос или думаю вообще переделать архитектуру хранения записей. Надеюсь вы мне поможете определиться ;)

На проекте есть 3 таблицы: Объект, к которым принадлежат Детали и Материалы. Мне нужно получить: Список объектов, у которых есть кол-во (items_count) принадлежащих к нему Детали+Материалы, а так же получить последнюю дату обновлению записи, т.е. пройтись по этим таблицам (по полю last_update) и вытащить последнюю таймстамп дату GREATEST() .

Поле status = 1 , item доступен или нет.
SELECT
	`Ob`.`id` AS `id`,
	`Ob`.`title` AS `title`,
	`Ob`.`poster` AS `poster` ,
        @count_details := (SELECT count(*) FROM game.Details D WHERE D.objectId = Ob.id AND D.status = 1 ),
	@count_materials := (SELECT count(*) FROM game.Materials Ma WHERE Ma.objectId = Ob.id AND Ma.status = 1 ),
	@count_details + @count_materials as items_count,
	@max_update_details := (SELECT MAX(D.last_update) FROM game.Details D WHERE D.objectId = Ob.id AND D.status = 1 ),
	@max_update_materials := (SELECT MAX(Ma.last_update) FROM game.Materials Ma WHERE Ma.objectId = Ob.id AND Ma.status = 1 ),
	GREATEST(
			`Ob`.`last_update`, @max_update_details, ifnull(@max_update_materials, 0 )
	) as last_update
FROM game.`Object` Ob
WHERE status=1
ORDER BY last_update DESC;


В принципе все это работает, но проблема в том, что это чудо долго будет обрабатываться с нарастанием записей. :(
Реально ли как-то оптимизировать этот запрос?

Я думаю, что при сохранении формы добавления/изменения Details или Materials пересчитывать их кол-во к принадлежащему объекту. И заносить в Object таблицу, в какую нибудь новую колонку, а не делать каждый раз столько вложенных запросов. Тоже самое и касается время изменения last_update.

Еще наткнулся на один вопрос, где во вложенном запросе добавлена переменная @i в качестве инкремента. Можно ли сделать, чтобы на момент вычисления максимального значения, можно было подсчитать кол-во найденных записей, (псевдокод):
SELECT MAX(D.last_update), @i := @i +1 
FROM game.Details D 
WHERE D.objectId = Ob.id;


Забыл кстати скинуть результаты Explain:
id |select_type        |table |type |possible_keys                             |key                           |key_len |ref   |rows   |Extra                                        |
---|-------------------|------|-----|------------------------------------------|------------------------------|--------|------|-------|---------------------------------------------|
1  |PRIMARY            |Ob    |ALL  |                                          |                              |        |      |139    |Using where; Using temporary; Using filesort |
5  |DEPENDENT SUBQUERY |D     |ref  |IX_Details_status_last_update             |IX_Details_status_last_update |2       |const |25909  |Using where                                  |
4  |DEPENDENT SUBQUERY |Ma    |ref  |IX_Materials_status,IX_Materials_objectId |IX_Materials_status           |2       |const |125431 |Using where                                  |
3  |DEPENDENT SUBQUERY |D     |ref  |IX_Details_status_last_update             |IX_Details_status_last_update |2       |const |25909  |Using where                                  |
2  |DEPENDENT SUBQUERY |Ma    |ref  |IX_Materials_status,IX_Materials_objectId |IX_Materials_status           |2       |const |125431 |Using where                                  |


Вот схема Таблиц:
16171431db77435cb95d8031b189c2ed.png

Спасибо за внимание!
  • Вопрос задан
  • 944 просмотра
Подписаться 2 Комментировать