簡體   English   中英

避免在內部選擇中進行全表掃描

[英]Avoid full table scan in inner select

我在MySQL中選擇了以下內容,它會產生正確的結果,但是執行起來會花費不必要的時間:

SELECT tblGPSDevices.Email, tblLoc.Lat, tblLoc.Lon, tblLoc.Radius, tblLoc.CreationTimeStamp, tblTrackedUsers.ID, tblTrackedUsers.TrackerDeviceID, tblTrackedUsers.TrackedDeviceID
    FROM tblTrackedUsers
    INNER JOIN tblGPSDevices ON tblTrackedUsers.TrackedDeviceID = tblGPSDevices.ID
    LEFT OUTER JOIN (
            SELECT A.DeviceID, A.Lat, A.Lon, A.Radius, A.CreationTimeStamp, A.ID 
            FROM tblLocations A 
            INNER JOIN (
                    SELECT DeviceID, MAX(CreationTimeStamp) AS CreationTimeStamp, MAX(ID) AS ID
                    FROM tblLocations
                    GROUP BY DeviceID
            ) AS B ON A.DeviceID = B.DeviceID
                AND A.CreationTimeStamp = B.CreationTimeStamp
                AND A.ID = B.ID                         
    ) AS tblLoc ON tblLoc.DeviceID = tblGPSDevices.ID
    WHERE tblGPSDevices.Validated = 0x01
    AND tblGPSDevices.Enabled = 0x01
    AND tblTrackedUsers.Validated = 0x01
    AND tblTrackedUsers.TrackerDeviceID = 1
    ORDER BY tblTrackedUsers.ID;

該查詢的運行速度比正常情況要慢得多,因為它會對tblLocations進行全表掃描。

這是真正減慢查詢速度的部分:

SELECT A.DeviceID, A.Lat, A.Lon, A.Radius, A.CreationTimeStamp, A.ID 
        FROM tblLocations A 
        INNER JOIN (
            SELECT DeviceID, MAX(CreationTimeStamp) AS CreationTimeStamp, MAX(ID) AS ID
            FROM tblLocations
            GROUP BY DeviceID
        ) AS B ON A.DeviceID = B.DeviceID
            AND A.CreationTimeStamp = B.CreationTimeStamp
            AND A.ID = B.ID 

這是解釋計划:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     tblTrackedUsers     ref     TrackerDeviceID,TrackedDeviceID     TrackerDeviceID     9   const   14  Using where; Using temporary; Using filesort
1   PRIMARY     tblGPSDevices   eq_ref  PRIMARY     PRIMARY     8   tblTrackedUsers.TrackedDeviceID     1   Using where
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    2073    
2   DERIVED     <derived3>  ALL     NULL    NULL    NULL    NULL    2073    
2   DERIVED     A   eq_ref  PRIMARY,DeviceID,CreationTimeStampIndex     PRIMARY     8   B.ID    1   Using where
3   DERIVED     tblLocations    index   NULL    DeviceID    8   NULL    174058  

即使我只需要該表中DeviceID的一小部分,它也會對tblLocations進行全表掃描。

我只需要查看從此部分返回的DeviceID:

INNER JOIN tblGPSDevices ON tblTrackedUsers.TrackedDeviceID = tblGPSDevices.ID
WHERE tblTrackedUsers.TrackerDeviceID = 1

但是很遺憾,tblTrackedUsers.TrackedDeviceID在內部選擇中不可見。 所以如果我加

WHERE DeviceID = tblTrackedUsers.TrackedDeviceID

正上方

GROUP BY DeviceID

這是行不通的。

我該如何優化此查詢?

僅涉及相關字段的表的結構:

tblGPSDevices:


ID | 電郵| 已驗證| 已啟用


tbl位置:


ID | 設備ID | 緯度| 隆| 半徑| CreationTimeStamp


tblTrackedUsers:


ID | TrackerDeviceID | TrackedDeviceID | 已驗證


tblLocations.DeviceID,tblTrackedUsers.TrackerDeviceID和tblTrackedUsers.TrackedDeviceID是指向tblGPSDevices.ID的外鍵

該查詢的作用:

該查詢應返回用戶正在跟蹤的tblGPSDevices中的所有設備,以及tblLocations中它們的最后位置。 確定用戶正在跟蹤哪些設備的方法由tblTrackedUsers確定:從tblTrackedUsers中選擇TrackedDeviceID,其中TrackerDeviceID = some_value

我確實找到了答案,並將發布以供將來參考。 從2秒開始,查詢速度加快了。 至0.0179秒 那是巨大的收獲。

關鍵是在其中添加一個內部選擇:

SELECT DeviceID, MAX(CreationTimeStamp) AS CreationTimeStamp, MAX(ID) AS ID
FROM tblLocations
GROUP BY DeviceID

為了避免全表掃描,因為我們只對tblTrackedUsers.TrackedDeviceID =的DeviceID感興趣。 現在,此選擇如下所示:

 SELECT C.DeviceID, MAX(C.CreationTimeStamp) AS CreationTimeStamp, MAX(C.ID) AS ID
 FROM tblLocations C
         INNER JOIN (
              SELECT ID, TrackerDeviceID, TrackedDeviceID,  TrackedName, AccessCode, Validated FROM tblAllowedUsers WHERE TrackerDeviceID = 1 AND Validated=0x01
          ) AS D ON D.TrackedDeviceID = C.DeviceID
  GROUP BY DeviceID

現在是全部選擇:

SELECT tblGPSDevices.Email, tblLoc.Lat, tblLoc.Lon, tblLoc.Radius, tblLoc.CreationTimeStamp, tblTrackedUsers.ID, tblTrackedUsers.TrackerDeviceID, tblTrackedUsers.TrackedDeviceID
    FROM tblTrackedUsers
    INNER JOIN tblGPSDevices ON tblTrackedUsers.TrackedDeviceID = tblGPSDevices.ID
    LEFT OUTER JOIN (
            SELECT A.DeviceID, A.Lat, A.Lon, A.Radius, A.CreationTimeStamp, A.ID 
            FROM tblLocations A 
            INNER JOIN (
                SELECT C.DeviceID, MAX(C.CreationTimeStamp) AS CreationTimeStamp, MAX(C.ID) AS ID
            FROM tblLocations C
                INNER JOIN (
                    SELECT ID, TrackerDeviceID, TrackedDeviceID,  TrackedName, AccessCode, Validated FROM tblAllowedUsers WHERE TrackerDeviceID = 1 AND Validated=0x01
                ) AS D ON D.TrackedDeviceID = C.DeviceID
            GROUP BY DeviceID
            ) AS B ON A.DeviceID = B.DeviceID
                AND A.CreationTimeStamp = B.CreationTimeStamp
                AND A.ID = B.ID                         
    ) AS tblLoc ON tblLoc.DeviceID = tblGPSDevices.ID
    WHERE tblGPSDevices.Validated = 0x01
    AND tblGPSDevices.Enabled = 0x01
    AND tblTrackedUsers.Validated = 0x01
    AND tblTrackedUsers.TrackerDeviceID = 1
    ORDER BY tblTrackedUsers.ID;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM