2014-02-07 164 views
-1

內我有此查詢:快速的查詢速度變慢時,子查詢

SELECT timestmp 
    FROM devicelog 
    WHERE device_id = 5 
    ORDER BY id DESC LIMIT 1 

這需要小於0.001秒的讀取,但一旦我把它放在一個子查詢,它會減慢至3.05秒。任何理由爲什麼這樣做,或者我可以如何補救?

這裏是第二個查詢(這是一個我想優化):

SELECT device.id, 
    (SELECT timestmp 
    FROM devicelog 
    WHERE device_id = device.id 
    ORDER BY id DESC LIMIT 1) as timestmp 
FROM device 

表「設備」只有像10-15記錄它(devicelog有幾百萬),所以我會假設它在每條記錄中都是1乘1,然後執行子查詢,但顯然它正在做其他事情。 devicelog的PK就是id,而設備中的PK也是它的id。 devicelog上有一個索引timestmp(這是一個日期時間)和device_id,這也是一個FK回devicelog。還有其他的指標,但它們是不相關的(比如名稱,描述等)。

我只是它需要遍歷設備,然後顯示最後的時間戳記錄。

如果我列出每個設備在PHP中,然後分別進行第一次查詢,將執行非凡的好,但我想這樣做在一個整個查詢。就像,我可以做類似(僞):

foreach($row in <devicelog>) 
    query('<first query> where id = $row[id]') 

做一個完整的加盟將是對devicelog太貴了,只是因爲高計數。

回答

1

根據提供的第一個答案的評論,您的問題和疑問不符合您的要求。

你可以做的是在每臺設備上預聚合獲得最大ID登錄,然後再加入,爲設備的主要清單...

SELECT 
     d.name, 
     d.id, 
     DeviceMax.lastTime 
    from 
     device d 
     LEFT JOIN (select dl.device_id, 
          max(dl.timestamp) lastTime 
         from 
          devicelog dl 
         group by 
          dl.device_id) as DeviceMax 
      ON d.id = DeviceMax.device_id 

現在,如果你需要從設備日誌中特定條目其他的東西,我們可以只添加到該...

LEFT JOIN devicelog dl2 
    on DeviceMax.Device_id = dl2.Device_id 
    AND DeviceMax.lastTime = dl2.timestamp 

那麼你可以從添加到您的查詢「DL2」別名得到任何其他列。

此外,爲您的設備日誌表,我會對(DEVICE_ID,時間戳)

評論作者反饋的覆蓋指數

然後我會提供這個作爲你一個建議,這是當有人需要「最高數量」或「最多」某種東西或「最近期數量」等網絡開發領域時,這種情況也很常見。

非常規化您的設備表,只有一個方面:爲LastDeviceLogID。然後,每當你DeviceLog中添加了一個條目,你只需要使用一個INSERT觸發器,做後...

update Device 
    set LastDeviceLogID = newRecord.DeviceLogID 
    where ID = newRecord.Device_ID 

列可能不準確,但原則是存在的。這樣一來,你永遠需要做一個LIMIT 1,MAX()等,並通過你的數百萬條記錄,你可以得到儘可能簡單地做

SELECT 
     d.name, 
     d.id, 
     dl.timestamp, 
     dl.othercolumns 
    from 
     device d 
     LEFT JOIN devicelog dl 
      on d.LastDeviceLogID = dl.DeviceLogID 
+0

試過了,大約需要7秒。 device_id(PK)和時間戳有幾個索引。 –

+0

@RalphWiggum,非規範化技術的修訂答案 – DRapp

+0

是的,我想插入觸發器將是最好的方式來做到這一點,但試圖避免使用它。 –

1

嘗試這與內部聯接

SELECT d.id, dl.timestamp 
    FROM device d 
    INNER JOIN devicelog dl 
    ON dl.device_id = d.id 
    ORDER BY d.id DESC LIMIT 1 

列出所有的設備,你可以考慮在GROUP BY

SELECT d.id, dl.timestamp 
    FROM device d 
    INNER JOIN devicelog dl 
    ON dl.device_id = d.id 
    GROUP BY d.id 
    ORDER BY d.id DESC 

編輯:

如果你有很多指標,THN更好地索引你列ID

試試這個

ALTER TABLE `device` ADD INDEX `id` (`id`) 
+0

這是罰款的設備只是一排,但我需要列出所有設備以及最後一個設備紀錄。 –

+0

查看編輯後的答案以適合您的需求 –

+0

由於「LIMIT 1」,仍然只返回1行。 –