我正在将脚本升级到带有新数据库布局的新版本。升级开始很好,但慢慢开始花费越来越多的时间来进行相同的查询。有问题的查询如下:
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有大约200万条记录。
oldtable_user和newtable_user有大约70,000条记录。
该查询首先执行速度非常快,但慢慢开始加起来,几个小时后执行大约需要30秒。当脚本升级时,这些表根本不会改变,因此我不确定瓶颈在哪里。随着OFFSET变量的增长,查询似乎变慢了。
这是EXPLAIN:
+----+-------------+---------+--------+-----------------+-----------------+---------+-----------------------------------+-------+-------------+
| 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配置选项,尽管它有所改进,但并不多。有什么建议吗?
答案 0 :(得分:1)
看看ORDER BY … LIMIT Performance Optimization的完整性,尽管你似乎没有做错任何事情。
大OFFSET
s很慢。在某一点之后没有解决这个问题。
你说你一次打包200条记录。为什么不做一个查询并读取所有70,000行?事实上这会更快。
答案 1 :(得分:0)
@cletus:有近200万条记录,但它仍然是一个好主意。对于MySQL来说,从该查询中获取200或20,000行是非常相同的,所以我认为它应该可行。
不幸的是,当我尝试在我的PHP脚本中执行此操作时,我得到了一个“Prematue end of scripts header”。经过大量的调试后,我确定它不是PHP内存限制或最大执行时间,但它仍然会发生。我能够通过控制台运行该查询,有时通过PHPMyAdmin运行,但不能在我的脚本中运行。我发现我的脚本在有一个小的OFFSET(300,000)时运行查询,但是如果我将OFFSET增加到700,000或1,500,000它会抛出内部服务器错误。所以我的问题是:在mysql_query()或mysql_fetch_array()上是否有任何类型的超时或其他东西?
顺便说一句:不确定我是否应该将此作为一个新问题发布。