2013-10-07 50 views
3

這裏的查詢:如何提高此MySQL查詢的速度?

SELECT 
u.uid as UID, 
fuo.uid as FUO_UID, 
fo.prid as FO_NAME 
FROM 
users u 
LEFT OUTER JOIN firstpoint_users_organisations fuo ON (u.uid=fuo.uid) 
LEFT OUTER JOIN firstpoint_organisations fo ON (fo.nid=fuo.nid) 
WHERE 
u.status=1 AND u.uid>1 
ORDER BY u.uid 
LIMIT 3; 

以及表:

users 
+------------------+------------------+------+-----+---------+----------------+ 
| Field   | Type    | Null | Key | Default | Extra   | 
+------------------+------------------+------+-----+---------+----------------+ 
| uid    | int(10) unsigned | NO | PRI | NULL | auto_increment | 
| name    | varchar(60)  | NO | UNI |   |    | 
| status   | tinyint(4)  | NO |  | 0  |    | 
+-----------------------------------------------------------------------------+ 

firstpoint_users_organisations 
+-------+------------------+------+-----+---------+-------+ 
| Field | Type    | Null | Key | Default | Extra | 
+-------+------------------+------+-----+---------+-------+ 
| nid | int(10) unsigned | NO | PRI | 0  |  | 
| uid | int(10) unsigned | NO | PRI | 0  |  | 
+-------+------------------+------+-----+---------+-------+ 

firstpoint_organisations 
+----------+------------------+------+-----+---------+-------+ 
| Field | Type    | Null | Key | Default | Extra | 
+----------+------------------+------+-----+---------+-------+ 
| nid  | int(10) unsigned | NO | PRI | 0  |  | 
| prid  | varchar(32)  | NO |  |   |  | 
+------------------------------------------------------------+ 

我希望顯示users.uidfirstpoint_organisations.pridusers每一行,即使有些用戶不會有prid,其中case我顯示NULL(因此左外連接)。連接應該如下:

users 
uid -  firstpoint_users_organisations 
    \---->uid 
      nid -   firstpoint_organisations 
       \-------->nid 
          prid 

所以每個用戶(用戶)的用戶ID(UID),並組織他們正在與(firstpoint_users_organisation)相關的有一個節點ID(NID)並存儲這種關聯。該組織的詳細信息將存儲在firstpoint_organisations中。

因此,每個用戶都有一個prid,但如果他們不這樣做,請顯示NULL。

現在,如果我在firstpoint_users_organisations然後firstpoint_organisations上做了INNER JOIN,我得到了很好的查詢速度(上面的查詢在0.02秒內運行)。但是,當我同時切換到LEFT OUTER JOIN時,我可以獲得所有用戶,prid或者沒有prid,上面的查詢需要大約90秒的時間才能運行。

有什麼我可以做的,以加快這個查詢?有約。在users表中有70000行,但即使使用LIMIT 3,使INNER JOIN成爲左外連接也需要很長時間。有趣的是,查詢花費的時間與LIMIT 30一樣多,所以我認爲我的查詢存在根本性問題。

EXPLAIN的要求:

+----+-------------+-------+--------+---------------+---------+---------+-----------------------+-------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref     | rows | Extra          | 
+----+-------------+-------+--------+---------------+---------+---------+-----------------------+-------+----------------------------------------------+ 
| 1 | SIMPLE  | u  | range | PRIMARY  | PRIMARY | 4  | NULL     | 13152 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | fuo | index | NULL   | PRIMARY | 8  | NULL     | 3745 | Using index         | 
| 1 | SIMPLE  | fo | eq_ref | PRIMARY  | PRIMARY | 4  | dbdb-dbdb_uat.fuo.nid |  1 |            | 
+----+-------------+-------+--------+---------------+---------+---------+-----------------------+-------+----------------------------------------------+ 
3 rows in set (0.00 sec) 
+2

請發表這一聲明的'EXPLAIN'。 – Kermit

+1

您的firstpoint_users_organisations表有一個問題是有可能有2個PRIMARY鍵?這聽起來對我來說實際上有點奇怪。 – Wikunia

+0

我已經添加了說明,謝謝。 FUO表中的2個主鍵看起來很奇怪,謝謝你的注意。 – njp

回答

1

您所查詢的是毫無意義的(因爲uid > 1將包括所有,但使用的UID索引的用戶之一),所以使用IGNORE INDEX提示爲該指數:

SELECT 
    u.uid as UID, 
    fuo.uid as FUO_UID, 
    fo.prid as FO_NAME 
FROM users u IGNORE INDEX (uid) 
LEFT JOIN firstpoint_users_organisations fuo ON u.uid=fuo.uid 
LEFT JOIN firstpoint_organisations fo ON fo.nid=fuo.nid 
WHERE u.status=1 
AND u.uid > 1 
ORDER BY u.uid 
LIMIT 3 

你應該把一個索引users(status),這可能會給你一些好處,如果有足夠的行狀態!= 1

這是很期望改變限制將沒有任何效果,因爲70000行必須進行排序之前的限制適用於知道行是返回第一個行 - 極限影響不大,除了少行返回到客戶端(少逗號IO)


我在「更少的代碼是好的」的信徒,所以從嚴格的風格一點我已刪除非必要的代碼您的查詢:

  • 刪除OUTER因爲沒有其他種類的左連接
  • 刪除括號加盟條件,因爲你不需要「時間
1

我會用在u.status唯一索引,u.uid的,因爲MySQL已經做出全掃描一下,哪些條目具有狀態= 1我想。

我希望它的速度更快之後;)