多くの場合、インデックスを追加すると役立ちますが、別のサブクエリを結合するサブクエリがあるため、現在のテーブルにインデックスを追加しても速度を上げることはできません。ここでインデックスを使用できる唯一の方法は、一時テーブルを作成することです。
したがって、Markusが指摘したように、クエリをいくつかの小さなクエリに分割して、結果を一時テーブルに保存する必要があります。それらにインデックスを追加して、うまくいけばクエリを高速化することができます。大きなクエリをいくつかの小さなクエリに分割することのもう1つの良い点は、どの部分が遅いかをより適切にプロファイリングして修正できることです。
また、1つのサブクエリを2回使用しましたが、結果がキャッシュされなかったため、パフォーマンスが低下しました。
これを行う方法の例を次に示します。
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;