2015-06-15 49 views
0

我有一個大的MySQL查詢,實際上返回的結果很好,但它很慢。如何提高我的朋友列表MySQL查詢?

SELECT DISTINCT 
    username, 
    user.id as uid, 
    email, 
    ui.gender, 
    ui.country, 
    ui.birthday, 
    IF(last_activity_date >= now() - INTERVAL 1 HOUR, 1, 0) as is_online, 
    p.thumb_url, 
    friend_request.id as sr_id, 
    IF(ul.id IS NOT NULL, 1, 0) as st_love, 
    DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(birthday, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(birthday, '00-%m-%d')) AS age 

FROM friend_request 

JOIN user ON (user.`id` = friend_request.`to_user_id` 
        OR 
        user.`id` = friend_request.`from_user_id`) 
       AND user.`id` != '$user_id' 
       AND friend_request.`status` = '1' 

JOIN user_info ui ON user.`id` = ui.`user_id` 

JOIN photo p ON ui.`main_photo` = p.`id` 

LEFT JOIN user_love ul ON ul.`to_user_id` = user.`id` 
         AND ul.`from_user_id` = $user_id 

WHERE (friend_request.`to_user_id` = '$user_id' 
    OR friend_request.`from_user_id` = '$user_id') 
ORDER BY friend_request.id DESC 
LIMIT 30 

「$ user_id」是登錄用戶的ID。

這裏是「friend_request」的表結構:

CREATE TABLE `friend_request` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `from_user_id` int(11) DEFAULT NULL, 
    `to_user_id` int(11) DEFAULT NULL, 
    `date` datetime DEFAULT NULL, 
    `seen` int(11) DEFAULT '0', 
    `status` int(11) DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `from_user_id` (`from_user_id`), 
    KEY `to_user_id` (`to_user_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; 

你能幫我改善查詢?

我還沒有複製其他表的表結構,因爲經過一些測試後,「優化問題」似乎來自friend_request表。

謝謝!

編輯:

這裏是「解釋」給我:

enter image description here

+0

考慮提供一個數據集和所需的結果集。 – Strawberry

+2

做左連接而不是右連接。 (當然,你必須將表格左移<-> ......)這是可讀性的真正提高! (大多數人都有足夠的左連接問題,並且在正確加入時會感到困惑......) – jarlh

+0

您是否從應用程序調用此應用程序?可能可以在應用程序代碼中執行一些業務邏輯(所有if/then語句和日期轉換),並將參數化列表傳遞給MySql以減輕數據庫上的一些處理。我同意@jarlh使用左連接,而不是正確的。 – ragerory

回答

1

你應該看看查詢計劃或使用關鍵字嘗試Explainhttps://dev.mysql.com/doc/refman/5.5/en/using-explain.html,這樣你可以找到查詢的哪些部分花費最長時間並優化它們。

東西跳出來對我說:

1)您可能需要降低您的加入,或優化他們

2)您可能需要一些指標

3)你有一個OR聲明在where子句中,哪個可能影響緩存查詢計劃,我在tsql中看到了一個Or查詢緩存問題。不知道這是否會影響mysql。 https://dev.mysql.com/doc/refman/5.1/en/query-cache.html

編輯:格式化,發現出來的照片表連接是必要的,目前正在選擇

+0

啊謝謝,錯過了那長選 –

+0

感謝您的回答。 1) - >鏈接到我的查詢的第二個IF語句。根據另一位用戶的建議,我正在將IF語句移出查詢,因此我不再需要這部分查詢。它可以節省一些毫秒。 2)我已經在表格上有一些索引。但也許我可以改進這部分。 – fraxool

+0

@fraxool這裏真正的關鍵是使用'Explain'關鍵字,每個查詢已經被更多的信息優化比您所提供和解釋工作重點將採取那些東西進去(索引類型的連接,,等等)。我們不得不玩猜測和檢查而不打算使用它。 –

0

我會寫這樣的查詢的數據。 (我也有資格在查詢中提及全部列,username,email,last_activity_date)。我也會將它作爲帶有綁定佔位符的準備語句來執行,而不是將$user_id變量包含在SQL文本中。我們假設$user_id的內容被稱爲「安全」,或者已被妥善地轉義,以避免SQL注入。

SELECT username 
     , user.id AS uid 
     , email 
     , ui.gender 
     , ui.country 
     , ui.birthday 
     , IFNULL((last_activity_date >= NOW() - INTERVAL 1 HOUR),0) AS is_online 
     , p.thumb_url 
     , sr.id          AS sr_id 
     , ul.id IS NOT NULL       AS st_love 
     , TIMESTAMPDIFF(YEAR,ui.birthday,DATE(NOW())) AS age 
    FROM (
      (SELECT frf.id 
        , frf.to_user_id AS user_id 
       FROM friend_request frf 
       WHERE frf.to_user_id <> '$user_id' 
       AND frf.from_user_id = '$user_id' 
       AND frf.status = '1' 
       ORDER BY frf.id DESC 
       LIMIT 30 
      ) 
      UNION ALL 
      (SELECT frt.id 
        , frt.from_user_id AS user_id 
       FROM friend_request frt 
       WHERE frt.from_user_id <> '$user_id' 
       AND frt.to_user_id = '$user_id' 
       AND frt.status = '1' 
       ORDER BY frt.id DESC 
       LIMIT 30 
      ) 
      ORDER BY id DESC 
      LIMIT 30 
     ) sr 
    JOIN user ON user.id = sr.user_id 
    JOIN user_info ui ON ui.user_id = user.id 
    JOIN photo p ON p.id = ui.main_photo 
    LEFT 
    JOIN user_love ul 
     ON ul.to_user_id = user.id 
    AND ul.from_user_id = '$user_id' 

    ORDER BY sr.id DESC 
    LIMIT 30 

注意事項:(像原來的查詢)

視圖sr旨在通過id擺脫friend_request最多30行,下令降直列

它看起來像原來的查詢打算查找指定的$user_id位於from_to_列中的行。

的MySQL更早的版本會產生涉及OR謂詞JOIN操作查詢了一些非常討厭的執行計劃。對於通常的解決方法是使用返回的UNION ALLUNION操作從兩個單獨的SELECT語句...每個SELECT可以被優化以使用適當的索引。

一旦我們從sr該結果集,查詢的其餘部分是相當簡單的。

+0

哇!非常感謝你。我只是在查詢中出現SQL語法錯誤,我無法從中找到它:'#1064 - 您的SQL語法錯誤;檢查對應於你的MySQL服務器版本的行11' – fraxool

+0

哎呀「AS年齡((SELECT frf.id,frf.to_user_id FROM friend_request AS user_ID的」使用附近的正確語法手冊,它之前只是缺少一個右括號'AS – spencer7593

+0

age'就在最後一個'#1054 - 不詳列在「fr.user_id「上clause''你能幫助非常感謝你 – fraxool