Другим способом является использование ЛЕВЫХ СОЕДИНЕНИЙ вместо подзапроса.
SELECT
t.uuid
, t.stamp AS t_stamp
, t_next.stamp AS t_next_stamp
, TIME_TO_SEC(TIMEDIFF(t_next.stamp, t.stamp)) AS diff
FROM
ttt AS t
LEFT JOIN ttt AS t_prev ON (
t_prev.uuid = t.uuid
AND t_prev.stamp < t.stamp
)
INNER JOIN ttt AS t_next ON (
t_next.uuid = t.uuid
AND t_next.stamp > t.stamp
)
LEFT JOIN ttt AS t_before_next ON (
t_before_next.uuid = t.uuid
AND t_before_next.stamp > t.stamp
AND t_before_next.stamp < t_next.stamp
)
WHERE
t_prev.id IS NULL -- no t_prev so t is the first record
AND t_before_next.id IS NULL -- no t_before_next so t_next is the second record
-- filter data by your criteria, per day for example.
-- you will need to "duplicate" filtering conditions for t_prev and t_next
ORDER BY
uuid
=>
uuid t_stamp t_next_stamp diff
0ccf-94e0-ce72-8092-1975-5bea-6131-c719 2020-01-02 14:11:48 2020-01-02 15:55:42 6234
60b5-d062-5829-c11d-5b71-5d85-075b-a3c5 2020-01-01 17:00:28 2020-01-01 17:01:30 62
6610-a9df-358d-0065-beb8-cea1-82a6-3258 2020-01-02 17:16:33 2020-01-02 17:21:20 287
c193-a46f-1104-3ee3-7387-94a8-ef32-a85e 2020-01-02 18:40:40 2020-01-02 18:40:49 9
c5d9-acba-9a12-aacb-cf45-c5a9-2b8d-314c 2020-01-02 15:46:41 2020-01-02 15:56:33 592
Предупреждение:
В приведенном выше запросе будут пропущены записи с та же марка. Если они вам нужны, вы должны внести изменения в условия соединения:
с
t_prev.stamp < t.stamp
на
t_prev.stamp <= t.stamp AND t_prev.id < t.id
et c
Затем вы можете использовать запрос для получения AVG:
-- explain
SELECT
AVG(TIME_TO_SEC(TIMEDIFF(t_next.stamp, t.stamp))) AS avg_diff
FROM
ttt AS t
LEFT JOIN ttt AS t_prev ON (
t_prev.uuid = t.uuid
AND t_prev.stamp < t.stamp
)
INNER JOIN ttt AS t_next ON (
t_next.uuid = t.uuid
AND t_next.stamp > t.stamp
)
LEFT JOIN ttt AS t_before_next ON (
t_before_next.uuid = t.uuid
AND t_before_next.stamp > t.stamp
AND t_before_next.stamp < t_next.stamp
)
WHERE
t_prev.id IS NULL
AND t_before_next.id IS NULL
=> 1436.8000 (для вашего набора данных)
Объяснить с помощью составного индекса (uuid, stamp):
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t NULL index ix_uuid_stamp ix_uuid_stamp 49 NULL 21 100.00 Using where; Using index
1 SIMPLE t_prev NULL ref ix_uuid_stamp ix_uuid_stamp 43 test.t.uuid 2 10.00 Using where; Not exists; Using index
1 SIMPLE t_next NULL ref ix_uuid_stamp ix_uuid_stamp 43 test.t.uuid 2 33.33 Using where; Using index
1 SIMPLE t_before_next NULL ref ix_uuid_stamp ix_uuid_stamp 43 test.t.uuid 2 10.00 Using where; Not exists; Using index
Используется «ref» вместо «зависимого подзапроса», как в принятом ответе. Что лучше зависит от ваших данных. Если отфильтрованный набор данных (когда вы фильтруете записи по дням) мал, «зависимый подзапрос» будет быстрее. Для больших отфильтрованных наборов данных я бы предпочел иметь «ref».
Не стесняйтесь тестировать оба способа и сообщите нам, что быстрее в вашем случае.