2012-02-28 139 views
3

我有以下SQL查詢:MySQL的左連接的時間太長

SELECT 
    upd.*, 
    usr.username AS `username`, 
    usr.profile_picture AS `profile_picture` 
FROM 
    updates AS upd 
LEFT JOIN 
    subscribers AS sub ON upd.uid=sub.suid 
LEFT JOIN 
    users AS usr ON upd.uid=usr.uid 
WHERE 
    upd.deleted='0' && (upd.uid='118697835834' || sub.uid='118697835834') 
GROUP BY upd.id 
ORDER BY upd.date DESC 
LIMIT 0, 15 

在那裏我得到的所有用戶(118697835834)的更新,使用左從另一個表他的個人資料圖片加入以及所有他的訂閱用戶更新,所以我可以在他的新聞源中顯示他們嗎?

然而,隨着更新,得到了越來越多這樣的查詢需要更多的時間來加載...現在使用CodeIgniter的探查,我可以看到的是,查詢需要1.3793 ...

現在,我已經創建大約18K的虛擬賬戶和訂閱我和反之亦然,所以我可以測試執行時間...我得到的時間是悲劇考慮到我在本地主機...

我也有一些索引,我想在用戶表中需要更多(用戶名和用戶名唯一),更新表(update_id爲唯一,用戶名爲索引)

我想我做錯了什麼讓這麼糟糕的結果...

編輯: 運行EXPLAIN EXTENDED結果:

Array 
(
    [0] => stdClass Object 
     (
      [id] => 1 
      [select_type] => SIMPLE 
      [table] => upd 
      [type] => ALL 
      [possible_keys] => i2 
      [key] => 
      [key_len] => 
      [ref] => 
      [rows] => 22 
      [filtered] => 100.00 
      [Extra] => Using where; Using temporary; Using filesort 
     ) 

    [1] => stdClass Object 
     (
      [id] => 1 
      [select_type] => SIMPLE 
      [table] => sub 
      [type] => ALL 
      [possible_keys] => 
      [key] => 
      [key_len] => 
      [ref] => 
      [rows] => 18244 
      [filtered] => 100.00 
      [Extra] => Using where 
     ) 

    [2] => stdClass Object 
     (
      [id] => 1 
      [select_type] => SIMPLE 
      [table] => usr 
      [type] => eq_ref 
      [possible_keys] => uid 
      [key] => uid 
      [key_len] => 8 
      [ref] => site.upd.uid 
      [rows] => 1 
      [filtered] => 100.00 
      [Extra] => 
     ) 

) 

EDIT2:SHOW創建表的 用戶表:

CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`uid` bigint(20) NOT NULL, 
`username` varchar(20) COLLATE utf8_unicode_ci NOT NULL, 
`email` text CHARACTER SET latin1 NOT NULL, 
`password` text CHARACTER SET latin1 NOT NULL, 
`profile_picture_full` text COLLATE utf8_unicode_ci NOT NULL, 
`profile_picture` text COLLATE utf8_unicode_ci NOT NULL, 
`date_registered` datetime NOT NULL, 
`activated` tinyint(1) NOT NULL, 
`closed` tinyint(1) NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `uid` (`uid`), 
UNIQUE KEY `username` (`username`) 
) ENGINE=MyISAM AUTO_INCREMENT=23521 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

認購表:

CREATE TABLE `subscribers` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`sid` bigint(20) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`suid` bigint(20) NOT NULL, 
`date` datetime NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=18255 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

更新表:

CREATE TABLE `updates` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`update_id` bigint(19) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`type` text COLLATE utf8_unicode_ci NOT NULL, 
`update` text COLLATE utf8_unicode_ci NOT NULL, 
`date` datetime NOT NULL, 
`total_likes` int(11) NOT NULL, 
`total_comments` int(11) NOT NULL, 
`total_favorites` int(11) NOT NULL, 
`category` bigint(20) NOT NULL, 
`deleted` tinyint(1) NOT NULL, 
`deleted_date` datetime NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `i1` (`update_id`), 
KEY `i2` (`uid`), 
KEY `deleted_index` (`deleted`) 
) ENGINE=MyISAM AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 
+2

使用EXPLAIN,以便您可以看到如何執行查詢 – 2012-02-28 13:10:39

+0

您是否完成了'EXPLAIN EXTENDED'(將其添加到您的查詢中) – 2012-02-28 13:10:51

+0

您是否索引了搜索和加入的所有內容? – 2012-02-28 13:12:35

回答

2

嘗試這一個(不GROUP BY):

SELECT 
    upd.*, 
    usr.username AS `username`, 
    usr.profile_picture AS `profile_picture` 
FROM 
     updates AS upd 
    LEFT JOIN 
     users AS usr 
      ON upd.uid = usr.uid 
WHERE 
    upd.deleted='0' 
    AND 
    (upd.uid='118697835834' 
    OR EXISTS 
     (SELECT * 
     FROM subscribers AS sub 
     WHERE upd.uid = sub.suid 
      AND sub.uid = '118697835834' 
    ) 
    ) 
ORDER BY upd.date DESC 
LIMIT 0, 15 

至少這在加入所用的列應被索引:updates.uidusers.uidsubscribers.suid

我還會在subscribers.uid上添加一個索引。

+0

這確實是希拉更快...我現在需要正確的索引以獲得更好的性能 – fxuser 2012-02-28 13:38:57

+2

@fxuser:編輯你的問題並添加表格的描述(列數據類型,索引和PK,FKs)。 – 2012-02-28 13:40:16

+0

我已經添加了3個表的所有展示創建 – fxuser 2012-02-28 13:47:39

0

應該用不了多長時間運行;你有'刪除'索引嗎?什麼是'GROUP BY ID'在做什麼?它應該是UID嗎?它可以出來,如果ID實際上只是一個自動增量,唯一的ID? (這將是昂貴的以及無意義)

+0

增加了刪除索引,沒有任何改變。 GROUP BY ID是查詢所必需的,以顯示我得到的所有更新,因爲通過刪除它將一直顯示1 .. – fxuser 2012-02-28 13:36:54

1

嘗試:

SELECT 
    upd.*, 
    usr.username AS `username`, 
    usr.profile_picture AS `profile_picture` 
FROM 
    updates AS upd 
LEFT JOIN 
    subscribers AS sub ON upd.uid=sub.suid 
LEFT JOIN 
    users AS usr ON upd.uid=usr.uid 
WHERE 
    upd.deleted=0 and upd.uid in (118697835834,118697835834) 
GROUP BY upd.id 
ORDER BY upd.date DESC 
LIMIT 0, 15 

注意'已經從數字值和位運算符除去變更爲常規的運營商。

+0

仍然具有相同的加載時間 – fxuser 2012-02-28 13:28:14

0

我認爲你最好將這個查詢分隔成用戶表上的select,然後將這些結果與訂戶表上的select進行聯合。

+0

也從users表開始,然後將更新結合到該表上。您的更新表格可能會比您的用戶大得多。 – Luc 2012-02-28 13:20:49

1

不使用連接,試試這個:

select *, 
     (select username from users where uid = upd.uid) as username, 
     (select profile_picture from users where uid = upd.uid) as profile_picture, 
from updates as upd 
WHERE 
    upd.deleted='0' && upd.uid='118697835834' 

(未測試!)

也許你得檢查是否存在的where子句與另一子選擇用戶。

另一種方法是在子選擇上進行連接,而不是在整個表上進行連接。這也可能會增加你的表現。

+0

避免'JOIN'的理由是?你可以在你的查詢中發佈一個比'JOIN'更好的'EXPLAIN'計劃嗎? – Naltharial 2012-02-28 13:54:05

+0

你似乎錯過訂閱表這裏雖然... – fxuser 2012-02-28 13:56:07

+0

@Naltharial:我還沒有建立數據庫,所以我沒有解釋。但我通過避免我的項目中的「連接」來提高性能。 – user1027167 2012-02-28 14:03:50