2010-02-27 116 views
3

我正在将脚本升级到具有新的数据库布局的新版本。升级开始正常,但慢慢开始需要更多的时间用于相同的查询。有问题的查询如下:使用多个JOIN优化MySQL查询

SELECT nuser.user_id, nfriend.user_id AS friend_user_id, f.time 
FROM oldtable_friends AS f 
JOIN oldtable_user AS u ON (u.user = f.user) 
JOIN newtable_user AS nuser ON (nuser.upgrade_user_id = u.id) 
JOIN oldtable_user AS uf ON (uf.user = f.friend) 
JOIN newtable_user AS nfriend ON (nfriend.upgrade_user_id = uf.id) 
LIMIT 200 
OFFSET 355600 

这里的OFFSET各不相同,因为数据是以200批次的批次获取的。

oldtable_friends拥有约2百万条记录。

oldtable_user和newtable_user有大约70,000条记录。

该查询一开始执行速度非常快,但慢慢开始累加,几个小时后执行大约需要30秒。脚本升级时,这些表格根本不会改变,所以我不确定瓶颈在哪里。看起来,随着OFFSET变量的增长,查询速度变慢。

这里是解释一下:

+----+-------------+---------+--------+-----------------+-----------------+---------+-----------------------------------+-------+-------------+ 
| id | select_type | table | type | possible_keys | key    | key_len | ref        | rows | Extra  | 
+----+-------------+---------+--------+-----------------+-----------------+---------+-----------------------------------+-------+-------------+ 
| 1 | SIMPLE  | nuser | ALL | upgrade_user_id | NULL   | NULL | NULL        | 71638 |    | 
| 1 | SIMPLE  | u  | eq_ref | PRIMARY,user | PRIMARY   | 4  | database.nuser.upgrade_user_id |  1 |    | 
| 1 | SIMPLE  | f  | ref | user,friend  | user   | 77  | database.u.user    | 20 |    | 
| 1 | SIMPLE  | uf  | eq_ref | PRIMARY,user | user   | 77  | database.f.friend    |  1 |    | 
| 1 | SIMPLE  | nfriend | ref | upgrade_user_id | upgrade_user_id | 5  | database.uf.id     |  1 | Using where | 
+----+-------------+---------+--------+-----------------+-----------------+---------+-----------------------------------+-------+-------------+ 

所有的桌子都被用在字段的索引。如果需要,我可以提供表结构。我一直在玩一些MySQL配置选项,尽管它有所改进,但并不多。有什么建议么?

回答

1

看看ORDER BY … LIMIT Performance Optimization的完整性,虽然你似乎没有做任何错误。

OFFSET s很慢。在某个点之后没有得到解决。

你说你一次批量处理200条记录。为什么不只是做一个查询并读取所有70,000行?这实际上会更快。

0

@cletus:有将近200万条记录,但它仍然是一个好主意。对于MySQL来说,从该查询中获取200或200行的行数几乎相同,所以我认为它应该可以工作。

不幸的是,当我尝试在我的PHP脚本中这样做时,我得到了“Prematue end of scripts header”。经过大量调试后,我确信它不是PHP内存限制或最大执行时间,但仍然会发生。我能够通过控制台运行该查询,并通过PHPMyAdmin 有时,但不能在我的脚本中运行。我发现我的脚本在有一个小的OFFSET(300,000)时运行查询,但如果我将OFFSET增加到700,000或1,500,000,它会引发内部服务器错误。所以我的问题是:是否有任何超时或mysql_query()或mysql_fetch_array()或其他?

顺便说一句:不知道我是否应该将此作为一个新问题发布。

+0

该问题似乎与默认FCGI配置选项,使其超过20秒后超时。您可以将它添加到您的fcgid.conf中: IPCCommTimeout 60 – Martin 2010-02-27 07:01:51