2012-02-28 97 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