3

这是查询:

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和,即使某些用户没有,在这种情况下我显示 NULL (因此左外连接)。连接应如下所示:firstpoint_organisations.pridusersprid

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

所以每个用户(users)都有一个用户id(uid),他们关联的组织(firstpoint_users_organisation)有一个节点id(nid)并存储这个关联。然后将组织的详细信息存储在 firstpoint_organisations 中。

所以每个用户都会有一个prid,但如果他们没有,则显示 NULL。

现在,如果我执行 INNER JOIN onfirstpoint_users_organisations然后 on firstpoint_organisations,我会得到很好的查询速度(上面的查询在 0.02 秒内运行)。但是,当我将两者都切换到 LEFT OUTER JOIN 时,我可以获得所有用户,prid或者没有prid,上面的查询需要大约 90 秒才能运行。

我能做些什么来加快这个查询吗?大约有。表中有 70,000 行users,但即使使用 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)
4

2 回答 2

1

使用 uid 上的索引您的查询毫无意义(因为uid > 1将包括除一个用户之外的所有用户),因此对该索引使用 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 行进行排序才能知道哪些行是要返回的第一行 - 限制几乎没有影响,除了返回给客户端的行更少(少逗号 IO)


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

  • 删除OUTER,因为没有其他类型的左连接
  • 删除了连接条件周围的括号,因为您不需要它们
于 2013-10-07T16:01:53.320 回答
1

为此,我会在 u.status,u.uid 上使用唯一索引,因为 mysql 必须进行全扫描才能查看,我认为哪些条目的状态 = 1。

我希望之后它会更快;)

于 2013-10-07T15:58:06.777 回答