如何提高MySQL查询的速度?

时间:2013-10-07 15:34:59

标签: 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.uid中的每一行显示firstpoint_organisations.pridusers,即使某些用户没有prid,在这种情况下我会显示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表中有70,000行,但即使使用LIMIT 3,使INNER JOIN成为LEFT OUTER JOIN需要花费大量时间。有趣的是,查询需要花费相同的时间来运行LIMIT 30,所以我认为我的查询存在根本性的错误。

按要求说明:

+----+-------------+-------+--------+---------------+---------+---------+-----------------------+-------+----------------------------------------------+
| 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 个答案:

答案 0 :(得分:1)

我会在u.status,u.uid上使用一个唯一索引,因为mysql必须使用fullscan来查看,我认为哪些条目的状态= 1。

我希望事后更快;)

答案 1 :(得分: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

非常期望更改LIMIT无效,因为在应用限制之前必须对排序70000行以了解哪些行是第一行return - 该限制几乎没有影响,除了返回较少的行到客户端(较少的逗号IO)


我相信“代码越少越好”,所以从严格的风格角度来看,我已从您的查询中删除了非必要的代码:

  • 已移除OUTER,因为没有其他类型的左连接
  • 删除了连接条件周围的括号,因为您不需要'em