2013-10-07 53 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我想。

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