简体   繁体   English

使用多个JOIN优化MySQL查询

[英]Optimizing MySQL query with several JOINs

I'm upgrading a script to a new version with a hole new database layout. 我正在将脚本升级到具有新数据库布局的新版本。 The upgrade starts fine but slowly starts taking more and more time for the same query. 升级开始很好,但慢慢开始花费越来越多的时间来进行相同的查询。 The query in question is the following: 有问题的查询如下:

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

The OFFSET here varies of course as data is fetched in batches of 200 records. OFFSET在这里当然不同,因为数据是以200个记录的批量提取的。

oldtable_friends has about 2 million records. oldtable_friends有大约200万条记录。

oldtable_user and newtable_user have around 70,000 records. oldtable_user和newtable_user有大约70,000条记录。

That query executes very fast at first but slowly starts to add up and after a couple of hours it takes about 30 seconds to execute. 该查询首先执行速度非常快,但慢慢开始加起来,几个小时后执行大约需要30秒。 Those tables don't change at all while the script is upgrading so I'm not sure where is the bottleneck. 当脚本升级时,这些表根本不会改变,因此我不确定瓶颈在哪里。 It seems that the query slows down as the OFFSET variable grows up. 随着OFFSET变量的增长,查询似乎变慢了。

Here is the EXPLAIN: 这是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 | 
+----+-------------+---------+--------+-----------------+-----------------+---------+-----------------------------------+-------+-------------+

All the tables have indexes on the fields being used. 所有表都在使用的字段上有索引。 I can provide the tables structure if needed. 如果需要,我可以提供表格结构。 I've been playing around a bit with MySQL configuration options and although it improved a bit, it wasn't much. 我一直在玩MySQL配置选项,尽管它有所改进,但并不多。 Any suggestions? 有什么建议么?

Take a look at ORDER BY … LIMIT Performance Optimization for completeness although you don't appear to be doing anything wrong as such. 看看ORDER BY ... LIMIT性能优化的完整性,尽管你似乎没有做任何错误。

Large OFFSET s are slow. OFFSET很慢。 There's no getting around that after a certain point. 在某一点之后没有解决这个问题。

You say you're batching 200 records at a time. 你说你一次打包200条记录。 Why not just do one query and read through all 70,000 rows? 为什么不做一个查询并读取所有70,000行? That will in fact be much faster. 事实上这会更快。

@cletus: There are almost 2 million records, but it's still a good idea. @cletus:有近200万条记录,但它仍然是一个好主意。 It takes almost the same for MySQL to get me 200 or 20,000 rows from that query so I think it should work. 对于MySQL来说,从该查询中获取200或20,000行几乎是一样的,所以我认为它应该可行。

Unfortunately when I try to do that in my PHP script I get a "Prematue end of scripts header". 不幸的是,当我尝试在我的PHP脚本中执行此操作时,我得到了一个“Prematue end of scripts header”。 After a lot of debugging I'm sure it's not a PHP memory limit or max execution time but it still happens. 经过大量的调试后,我确定它不是PHP内存限制或最大执行时间,但它仍然会发生。 I'm able to run that query just fine through console and sometimes through PHPMyAdmin but not in my script. 我能够通过控制台运行该查询, 有时通过PHPMyAdmin运行,但不能在我的脚本中运行。 I've found out that my script runs the query when there is a small OFFSET (300,000) but if I increase the OFFSET to 700,000 or 1,500,000 it throws the Internal Server Error. 我发现我的脚本在有一个小的OFFSET(300,000)时运行查询,但是如果我将OFFSET增加到700,000或1,500,000它会抛出内部服务器错误。 So my question is: is there any sort of timeout or something on mysql_query() or mysql_fetch_array() or else? 所以我的问题是:是否有任何类型的超时或mysql_query()或mysql_fetch_array()或其他什么?

BTW: not sure if I should post this as a new question. 顺便说一句:不确定我是否应将此作为一个新问题发布。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM