sql >> データベース >  >> RDS >> Mysql

クエリの最適化-時間がかかりすぎてサーバーを停止します

    多くの場合、インデックスを追加すると役立ちますが、別のサブクエリを結合するサブクエリがあるため、現在のテーブルにインデックスを追加しても速度を上げることはできません。ここでインデックスを使用できる唯一の方法は、一時テーブルを作成することです。

    したがって、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;
    


    1. SQLServerとSpectre/Meltdownの脆弱性

    2. MySQLはwhere句で結合します

    3. java.net.InetAddressjavaクラスはAlpineDockerコンテナのIPを解決しません

    4. Django、アップグレード後:MySQLサーバーがなくなりました