sql >> Databáze >  >> RDS >> Mysql

Optimalizace dotazu – trvá příliš dlouho a zastaví server

Přidání indexu v mnoha případech pomáhá, ale máte poddotaz, který se připojuje k jinému poddotazu, žádný index ve vaší aktuální tabulce vám nepomůže urychlit. Jediný způsob, jak zde můžete použít indexy, je vytvořit dočasnou tabulku.

Jak tedy Markus poukázal, musíte svůj dotaz rozdělit na několik menších, které uloží své výsledky do dočasné tabulky. Pak k nim můžete přidat indexy a doufejme, že urychlíte svůj dotaz. Další dobrá věc na rozdělení velkého dotazu na několik menších je, že můžete lépe profilovat, která část je pomalejší, a opravit ji.

Dvakrát jste také použili jeden dílčí dotaz, což je špatné pro výkon, protože výsledek nebyl uložen do mezipaměti.

Zde je příklad, jak to můžete udělat:

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. Výběr zaměstnanců s narozeninami v daném rozsahu pomocí Oracle SQL

  2. nástroj pro sledování dotazů mysql

  3. PostgreSQL:role nemá oprávnění se přihlásit

  4. Na co Hibernate mapuje booleovský datový typ při výchozím použití databáze Oracle?