2012-10-12 24 views
3

因此,通過一些SO用戶的幫助,我最終得到了一個邏輯上正確的MySQL查詢,用於我正在處理的任務:檢索反向按時間順序排列的ID列表允許用戶使用的新聞項目,某些類型的分組項目過濾到該組的單個代表。 (Phew!)馴服一個怪物MySQL查詢

還有一個明顯的問題,就是根據CakePHP的數據庫調用調試打印輸出,這個查詢非常笨重且速度很慢,達到了145000毫秒,哎。

是否有一個明智的辦法來馴服野獸像這樣的,或者我應該承認,我貪多,我可以在這裏咀嚼,尋找一個不太沉重的方法,將實現更多或更少類似的結果?所有建議表示讚賞

SELECT DISTINCT Uid.id, Uid.type 
    FROM (SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, 
       uids.type type 
      FROM uids 
      JOIN uids_uids ON uids_uids.uid_id = uids.id 
      JOIN aros_uids ON uids.id = aros_uids.uid_id 
      JOIN uids_uids ParentUids ON uids_uids.parent_id = ParentUids.uid_id 
      WHERE uids.type IN ('Document','Photo','Release','PreRelease', 
           'ArtworkResource','Event') 
      AND (uids.start_date IS NULL OR uids.start_date <= NOW()) 
      AND (uids.end_date IS NULL OR uids.end_date <= NOW()) 
      AND aros_uids.aro_id IN (3,2,86,1448) 
     ) Uid 
    JOIN (SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate 
      FROM uids JOIN uids_uids 
      ON uids_uids.uid_id = uids.id 
      GROUP BY uids_uids.parent_id, uids.type) T2 
    ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate 
    ORDER BY Uid.date DESC 
    LIMIT 100 

ETA:

好了,在第一遍,我轉身的子查詢到意見,所以現在查詢看起來像一個稍微更易於管理

SELECT DISTINCT Uid.id, Uid.type 
    FROM UidView Uid 
    JOIN UidView2 T2 
    ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate 
    WHERE Uid.aro_id IN (3,2,86,1448) 
    ORDER BY Uid.date DESC 
    LIMIT 100 

這一定幫助,將Cake的估計查詢時間從六位數降低到2500位左右。絕對是一個好開始!

+1

我給你一件事 - 那就是在一個查詢中查看很多'uids',並讓你的頭... – nickhar

+0

@nickhar告訴我有關它!在我的防守中,我沒有設置任何這些,我只是試圖慢慢地把它摔成一個易於管理的狀態。網站上的每個項目都有一個uid,通過uids_uids表連接到其他uid。有很多「WHERE uids_uids.uid_id = uid.id」類型的東西:) – thesunneversets

+1

你有我的同情心。一個uid_uid表!!尼斯。我會捕獲這種結構並將其提交給編碼恐怖。 – nickhar

回答

0

這裏是我想嘗試:

以每個派生的查詢和獨立運行的EXPLAIN針對每個。如評論所示,檢查任何缺少索引並在需要時添加的行。發佈您的EXPLAIN結果以獲得任何幫助。所以

EXPLAIN SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, .... 
EXPLAIN SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate .... 

如果添加索引不幫助或幫助不大,然後把每個子查詢到一個臨時表第一,並應用指標到它:這些表

CREATE TABLE temp_uid 
SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, 
      uids.type type 
     FROM uids 
     JOIN uids_uids ON uids_uids.uid_id = uids.id 
     JOIN aros_uids ON uids.id = aros_uids.uid_id 
     JOIN uids_uids ParentUids ON uids_uids.parent_id = ParentUids.uid_id 
     WHERE uids.type IN ('Document','Photo','Release','PreRelease', 
          'ArtworkResource','Event') 
     AND (uids.start_date IS NULL OR uids.start_date <= NOW()) 
     AND (uids.end_date IS NULL OR uids.end_date <= NOW()) 
     AND aros_uids.aro_id IN (3,2,86,1448); 

CREATE TABLE temp_t2 
SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate 
     FROM uids JOIN uids_uids 
     ON uids_uids.uid_id = uids.id 
     GROUP BY uids_uids.parent_id, uids.type; 

而且JOIN

SELECT DISTINCT Uid.id, Uid.type 
FROM temp_uid AS Uid 
JOIN temp_t2 AS T2 ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate 
ORDER BY Uid.date DESC 
LIMIT 100; 

正如我所提到的,您可能需要添加索引,並且可能會添加到臨時表中的這些列中:

ALTER TABLE temp_uid ADD INDEX parentDateIdx (parent_id, Uid.date); 
ALTER TABLE temp_t2 ADD INDEX parentMaxDateIdx (parent_id, maxdate); 

如果您需要刷新臨時表,只需截斷它們並對它們執行INSERT INTO temp_uid...SELECTINSERT INTO temp_t2...SELECT而不是CREATE...SELECT。存儲過程對此非常有用。

順便說一句,執行CREATE TABLE temp_t2...SELECT,我爲每個臨時表執行的方式可能無法創建最佳表結構,因此最好修改後續創建或從頭開始自己完成。

+0

乾杯,這看起來像一個明智的做法。我嘗試了類似的東西,但是使用視圖而不是表格。 CREATE TABLE可能產生更好的結果嗎? – thesunneversets

+0

我相信它應該,尤其是當您將索引添加到這些臨時表的列時。儘管如此,你確實需要進行測試。並且不要忽視爲所有這些uid的表添加索引。這裏是我的創建表格示例[鏈接](http://dev.mysql.com/doc/refman/5.0/en/create-table-select.html)上的文檔,並插入... select [link](http ://dev.mysql.com/doc/refman/5.1/en/insert-select.html) – Carlos