busidoway
@busidoway

Как оптимизировать SQL запрос?

Есть две таблицы:
devices: id_device
eventlog: id_event, id_device, id_place


В devices хранятся данные об устройствах. В eventlog - события. В devices на данный момент 5 записей, в eventlog ~1900. Необходимо вывести устройства и последнее событие для каждого.
id_event - код события,
id_device - код устройства,
id_place - код подразделения, к которым относятся устройства (т.е. в одном подразделении может быть несколько устройств)

Пример eventlog:
id_event 	| id_device 	| id_place
1		 | 1		 | 1
2		 | 1		 | 1
3		 | 2		 | 1
4		 | 2		 | 1
5		 | 3		 | 2
6		 | 3		 | 2
7		 | 4		 | 2
8		 | 4		 | 2

Запрос (выборка происходит по id_place):
SELECT d.*, ev1.*
       FROM devices d
       INNER JOIN eventlog ev1 ON d.id_device = ev1.id_device 
       AND ev1.id_event IN (SELECT MAX(id_event) FROM eventlog GROUP BY id_device)
       AND ev1.id_place IN(1,2,3,4) GROUP BY ev1.id_device

Запрос работает. Выводит все правильно, но долго. Примерно 0.8288 сек.
Можно ли как-то еще оптимизировать запрос?
  • Вопрос задан
  • 120 просмотров
Пригласить эксперта
Ответы на вопрос 2
В принципе GROUP BY в запросе будет сканировать всю таблицу в 90%. Можно конечно попробовать поиграться с составными индексами на таблицу логов. Запрос переписывать...
Самый простой способ, на мой взгляд, в исполнении и работает ad-hoc:
Добавьте поле в таблицу devices(назовем его lastidevent ) и сделайте триггер на вставку в таблицу eventlog, который будет обновлять поле lastidevent на вставляемый id_event в таблице devices. Затем в запросе соединять с таблицей логов по полю lastidevent.
Т.к. таблица devices не нагружена, то конкуренция будет минимальна. Правда, придется считаться с возросшими расходами на вставку логов.
Ответ написан
Комментировать
busidoway
@busidoway Автор вопроса
Решил задачу двумя запросами. Сначала вывел id устройств по id_place:
SELECT d.*, ev1.*
		FROM devices d
		INNER JOIN eventlog ev1 ON d.id_device = ev1.id_device
		AND ev1.id_place IN(1,2,3) GROUP BY ev1.id_device

Затем закинул полученный результат в массив php и в цикле сделал запрос по каждому устройству:
SELECT d.*, e.*
	FROM devices d INNER JOIN eventlog e ON e.id_device = d.id_device AND e.id_device = ".$val." ORDER BY e.id_event DESC LIMIT 1
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы