sql >> Database >  >> RDS >> Mysql

Query-optimalisatie -- duurt te lang en stopt de server

Het toevoegen van een index helpt in veel gevallen, maar je hebt een subquery die zich bij een andere subquery voegt, geen index op je huidige tabel kan je helpen versnellen. De enige manier waarop u hier indexen kunt gebruiken, is door een tijdelijke tabel te maken.

Dus zoals Markus al aangaf, moet je je query opsplitsen in een paar kleinere die hun resultaten in een tijdelijke tabel opslaan. Dan kunt u er indexen aan toevoegen en hopelijk uw zoekopdracht versnellen. Een ander voordeel van het opsplitsen van grote zoekopdrachten in een paar kleinere is dat je beter kunt profileren welk deel het langzamere is en dit oplost.

Je hebt ook twee keer een subquery gebruikt, wat slecht is voor de prestaties omdat het resultaat niet in de cache is opgeslagen.

Hier is een voorbeeld van hoe u dit zou kunnen doen:

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;


  1. SQL-weergave bewerkbaar maken

  2. Onze Microsoft Ignite-sessieopname is nu beschikbaar om te bekijken!

  3. MySQL ERROR 1045 (28000):Toegang geweigerd voor gebruiker 'bill'@'localhost' (met wachtwoord:JA)

  4. Is het in MySQL-trigger mogelijk om een ​​gebruikersvariabele in te stellen met NEW.col en die te gebruiken in de updatequery?