2017-06-26 22 views
1

我有三個表,它看起來像這樣MySQL的左連接只有最後一排十分緩慢

堡壘

|id|lat|lon| 

fort_sightings

|id|fort_id|team| 

fort_raids

|id|fort_id|raid_level| 

我需要獲取所有從forts行,然後選擇從fort_sightingsfort_raids最新信息,如果任何一個查詢。可能有多行fort_id具有相同的值,所以我需要最新的信息。

目前,我有這個,這可能不是最漂亮的

SELECT 
    * 
FROM 
    forts c 

LEFT JOIN fort_sightings o ON o.id = (
    SELECT 
     id 
    FROM 
     fort_sightings 
    WHERE 
     fort_id = c.id 
    ORDER BY 
     id DESC 
    LIMIT 1 
) 

LEFT JOIN fort_raids r ON r.id = (
    SELECT 
     id 
    FROM 
     fort_raids 
    WHERE 
     fort_id = c.id 
    ORDER BY 
     id DESC 
    LIMIT 1 
) 

但它是痛苦的緩慢,查詢接管10秒。 forts只有〜350行,所以它真的不應該花這麼長時間。我相信它來自JOIN中的所有SELECT查詢,但我不知道任何替代方案。

EXPLAIN explain query

+0

每一個問題與慢查詢涉及包含EXPLAIN'的'輸出。請看看如何獲​​得'EXPLAIN'的輸出並將其發佈在這裏。 – Mjh

+0

子查詢總是很慢,在這種情況下,如果我沒有弄錯,你正在爲每個o.id和r.id做一個子查詢。總是找到一種避免子查詢的方法。 – Goose

+0

爲了找到它爲什麼這麼慢,使用'explain'後面跟着這個查詢(在mysql命令行中),它​​會告訴你使用了哪些索引以及讀取了多少記錄。你可以改變你的代碼來使用索引或添加索引,如果它真的需要的話 – Tamar

回答

0

這是您的查詢:

SELECT * 
FROM forts c LEFT JOIN 
    fort_sightings o 
    ON o.id = (SELECT fs2.id 
       FROM fort_sightings fs2 
       WHERE fs.fort_id = c.id 
       ORDER BY fs2.id DESC 
       LIMIT 1 
       ) LEFT JOIN 
    fort_raids r 
    ON r.id = (SELECT fr2.id 
       FROM fort_raids fr2 
       WHERE fr2.fort_id = c.id 
       ORDER BY fr2.id DESC 
       LIMIT 1 
       ); 

我覺得很奇怪的是結構化的。但是,看看,如果這個工程:

  • fort_sightings(fort_id, id)
  • fort_raids(fort_id, id)

fort_id在索引的第一個鍵是很重要的。

如果這不起作用,那麼您可能需要修改查詢。

+0

第一個關鍵?我不知道這很重要。我會嘗試切換鍵盤,然後運行您的查詢,謝謝! – kopa

+0

我有兩個主鍵'id'和'fort_id',其中'id'使用'AUTO INCREMENT'。如果我嘗試切換它們,那麼'fort_id'是關鍵字1,那麼我得到這個:'1075 - 不正確的表格定義;只能有一個自動列,並且必須將其定義爲密鑰「 – kopa

+0

您不需要兩個主鍵。你需要我在答案中描述的複合索引。 –

0

除了來自Gordon的索引建議,您正在做一個相關的子查詢,這意味着對於堡壘表中的每個記錄,您都將重新運行查詢以查看和搜索。我想稍微改變拉所有的MAX()每堡壘從每個再加入...像

SELECT 
     c.id, 
     c.lat, 
     c.lon, 
     fs2.team, 
     fr2.raid_level 
    FROM 
     forts c 
     LEFT JOIN 
     (select fs.fort_id, max(fs.id) as MaxSightID 
       from fort_sightings fs 
       group by fs.fort_id) S 
      on c.id = s.fort_id 
      LEFT JOIN fort_sightings fs2 
       on s.MaxSightID = fs2.id 
     LEFT JOIN 
     (select fr.fort_id, max(fr.id) as MaxRaidID 
      from fort_raids fs 
      group by fr.fort_id) R 
      on c.ID = r.fort_id 
      LEFT JOIN fort_raids fr2 
      on r.MaxRaidID = fr2.id 

的第二部分左聯接回到原來的RAID和瞄準表拉相應的團隊,如果發現任何此類問題,請在最終結果中找到突襲級別。

0

如果您需要最有效的查詢,您應該添加列latest_fort_sighting_idlatest_fort_raid_idforts。MySQL沒有強大的功能,如物化視圖哈希加入像PostgreSQL,我們需要手動處理它們。不要忘記使用事務進行更新。

如果限制範圍爲forts,或者只能使用LEFT JOIN運行優化查詢。

select - SQL join: selecting the last records in a one-to-many relationship - Stack Overflow

SELECT forts.*, fs1.team, fr1.raid_level FROM forts 
LEFT JOIN fort_sightings fs1 ON fs1.fort_id = forts.id 
LEFT JOIN fort_sightings fs2 ON fs2.fort_id = forts.id AND fs1.id < fs2.id 
LEFT JOIN fort_raids fr1 ON fr1.fort_id = forts.id 
LEFT JOIN fort_raids fr2 ON fr2.fort_id = forts.id AND fr1.id < fr2.id 
WHERE fs2.id IS NULL AND fr2.id IS NULL AND forts.id > 5 ORDER BY forts.id LIMIT 5; 

enter image description here