2016-05-14 100 views
1

我有以下選擇:MySQL的選擇緩慢的,因爲順序按

SELECT a.userid, 
    (SELECT name FROM photos WHERE userid=a.userid AND type='profile' LIMIT 1) AS photo, 
    (SELECT attractive FROM photos WHERE userid=a.userid AND type='profile' LIMIT 1) AS attractive, 
    IF(a.domain="domanin.com",1,2) AS preferredDomain, 
    IF(a.domain LIKE "%domain.com",1,2) AS preferredSubDomain 
FROM users AS a 
WHERE a.gender = 1 
    AND a.visible = 1 
    AND a.active = 1 
    AND a.completed = 1 
    AND a.approved = 1 
HAVING photo IS NOT NULL 
ORDER BY preferredDomain ASC, 
    attractive DESC, 
    a.lastlogin DESC, 
    preferredSubDomain ASC 
LIMIT 100; 

這需要5-6秒來運行。

如果我刪除Order By需要0.23秒才能運行。

我假設這是因爲SELECT必須先生成內部SELECTS才能進行排序?這是正確的嗎?用戶表有60,000個條目。

任何人都可以提供一些建議,如何更好地構造此查詢?

+0

你有一個沒有'GROUP BY'的'HAVING'子句? – Stewart

回答

1

嘗試使用一個連接,而不是嵌套查詢,例如:在聯接語法

SELECT 
     a.userid, 
     p.name, 
     p.attractive, 
     IF(a.domain="domain.com",1,2) AS preferredDomain, 
     IF(a.domain LIKE "%domain.com",1,2) AS preferredSubDomain 
FROM users AS a 
JOIN photos AS p ON (p.userid = a.userid AND p.type = 'profile') 
WHERE 
     a.gender = 1 
     AND a.visible = 1 
     AND a.active = 1 
     AND a.completed = 1 
     AND a.approved = 1 
HAVING photo IS NOT NULL 
ORDER BY preferredDomain ASC, attractive DESC, a.lastlogin DESC, preferredSubDomain ASC 
LIMIT 100; 

文檔可以在這裏找到: http://dev.mysql.com/doc/refman/5.7/en/join.html

+0

兩個子查詢<原始查詢>中的限制1應在加入前考慮, 如果總共有相同的USERID和TYPE記錄,那麼此查詢應該工作,否則 ,否則GROUP BY將被需要。 – Hytool

+0

@Adam - 不要急於批准此解決方案。至少有三個與原始查詢不符的地方 - 'photo'沒有被定義,'JOIN'應該是'LEFT JOIN','吸引力不在'p'中。此外,它可能不會更快。 –

0

的子查詢都不是壞人。使用ORDER BY所有60K行必須在排序前進行評估。沒有ORDER BY可能更少的行需要查看。

@ StephanGarle對JOIN的建議應加快查詢速度,尤其是因爲兩個子查詢都被一個JOIN取代。

photos需要INDEX(type, userid)(以任一順序)。但更好的是有一個「覆蓋」指數:(type, userid, name, attractive),其中前兩個以任意順序排列,最後兩個以任意順序排列。

有兩種方式photoNULL -

  • 該行可能存在,但name可能是NULL,或者
  • 行是不可能存在的。 (也就是說,photos中沒有用於該用戶標識和類型'檔案'的行)。

這些是哪一個?要涵蓋這兩種情況,請使用LEFT JOIN

此指數(以任何順序列)可以幫助提高性能:

INDEX(gender, visible, active, completed, approved) 

所以......

SELECT a.userid, 
     p.name, 
     p.attractive, 
     IF(a.domain="domain.com", 1,2)  AS preferredDomain, 
     IF(a.domain LIKE "%domain.com", 1,2) AS preferredSubDomain 
    FROM users AS a 
    LEFT JOIN photos AS p 
       ON (p.userid = a.userid 
      AND p.type = 'profile') 
    WHERE a.gender = 1 
     AND a.visible = 1 
     AND a.active = 1 
     AND a.completed = 1 
     AND a.approved = 1 
     AND p.name IS NOT NULL 
    ORDER BY preferredDomain ASC, p.attractive DESC, a.lastlogin DESC, 
       preferredSubDomain ASC 
    LIMIT 100; 

我仍然不確定是否nameLEFT正確處理。