2010-02-27 141 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