Thêm chỉ mục giúp ích trong nhiều trường hợp, nhưng bạn có một truy vấn con tham gia một truy vấn con khác, không chỉ mục nào trên bảng hiện tại của bạn có thể giúp bạn tăng tốc. Cách duy nhất bạn có thể sử dụng các chỉ mục ở đây là tạo bảng tạm thời.
Vì vậy, như Markus đã chỉ ra, bạn cần chia truy vấn của mình thành một vài truy vấn nhỏ hơn để lưu trữ kết quả của chúng trong một bảng tạm thời. Hơn nữa, bạn có thể thêm chỉ mục cho chúng và hy vọng tăng tốc truy vấn của bạn. Một điều tốt khác khi chia truy vấn lớn thành một vài truy vấn nhỏ hơn là bạn có thể xác định rõ hơn phần nào chậm hơn và sửa phần đó.
Bạn cũng đã sử dụng một truy vấn con hai lần, điều này có hại cho hiệu suất do kết quả không được lưu vào bộ nhớ đệm.
Đây là một ví dụ về cách bạn có thể làm điều này:
DROP TEMPORARY TABLE IF EXISTS tmp_k;
CREATE TEMPORARY TABLE tmp_k
ENGINE=Memory
SELECT
gps_unit_location.*,
@i:= IF(((Speed_Kmh > 80) AND (@b = 0)), @i + 1, @i) AS IntervalID,
@r:= IF(((Speed_Kmh > 80) AND (@b = 0)), 1, @r + 1) AS RowNumber,
@b:= IF((Speed_Kmh > 80), 1, 0) AS IntervalCheck
FROM
gps_unit_location,
(SELECT @i:=0) i,
(SELECT @r:=0) r,
(SELECT @b:=0) b
ORDER BY
dt,
idgps_unit_location;
ALTER TABLE tmp_k ADD INDEX (IntervalID);
DROP TEMPORARY TABLE IF EXISTS tmp_max;
CREATE TEMPORARY TABLE tmp_max
ENGINE=Memory
SELECT
IntervalID,
MAX(RowNumber) AS MaxRowNo
FROM
temp_k
WHERE
IntervalCheck = 1
GROUP BY
IntervalID;
ALTER TABLE tmp_max ADD INDEX (IntervalID);
SELECT
k.idgps_unit,
MIN(k.dt) AS DT_Start,
MIN(IF(k.RowNumber = 1, k.Lat, NULL)) AS Latitude_Start,
MIN(IF(k.RowNumber = 1, k.Long, NULL)) AS Longitude_Start,
MIN(IF(k.RowNumber = 1, k.Speed_kmh, NULL) AS Speed_Start,
MAX(k.dt) AS DT_End,
MIN(IF(k.RowNumber = m.MaxRowNo, k.Lat, NULL)) AS Latitude_End
MIN(IF(k.RowNumber = m.MaxRowNo, k.Long, NULL)) AS Longitude_End
MIN(IF(k.RowNumber = m.MaxRowNo, k.Speed_kmh, NULL)) AS Speed_End,
AVG(Speed_kmh) AS Average_Speed,
gu.name,
gu.notes,
gu.serial
FROM
tmp_k AS k
INNER JOIN tmp_max AS m
USING(IntervalID)
INNER JOIN gps_unit AS gu
USING(idgps_unit)
INNER JOIN user AS u
ON (gu.idcustomer = u.idcustomer)
WHERE
(k.IntervalCheck = 1)
AND (u.iduser = 14)
GROUP BY
k.IntervalID,
k.idgps_unit;
DROP TEMPORARY TABLE tmp_k;
DROP TEMPORARY TABLE tmp_max;