2017-03-03 138 views
0

我有一個約400k行的用戶表,需要檢索其中一些(最多100),同時與其他表進行多個JOINS。 (使用mysql)如何優化這個慢sql查詢?

我的問題是,查詢目前有約800ms的執行時間(取46ms)。我的目標是優化查詢以減少執行時間。

我的初始查詢看起來是這樣的:

SELECT iduser, imageurl, birthdate, active, last_active, created, gender_idgender, orientation_idorientation, region_idregion, moji.moji_idmoji as moji_idmoji, status.value as status, requests.value as requestsRecv, requestssent.value as requestsSent, username.value as username, likecount.value as likeCount, reportcount.value as reportCount 
FROM user u 
    JOIN user_has_moji moji ON (u.iduser = moji.user_iduser) 
    JOIN user_has_data status ON (u.iduser = status.user_iduser AND status.datatype_iddatatype = 1) 
    JOIN user_has_data requests ON (u.iduser = requests.user_iduser AND requests.datatype_iddatatype = 3) 
    JOIN user_has_data requestssent ON (u.iduser = requestssent.user_iduser AND requestssent.datatype_iddatatype = 4) 
    JOIN user_has_data username ON (u.iduser = username.user_iduser AND username.datatype_iddatatype = 5) 
    JOIN user_has_data likecount ON (u.iduser = likecount.user_iduser AND likecount.datatype_iddatatype = 6) 
    JOIN user_has_data reportcount ON (u.iduser = reportcount.user_iduser AND reportcount.datatype_iddatatype = 7) 
WHERE banned = 0 AND active = 1 AND u.reviewstatus_idreviewstatus = 3 AND DATEDIFF(last_active,'2017-03-03 10:06:36') >=0 AND DATEDIFF(birthdate, '1999-03-03 15:06:36') >= 0 AND DATEDIFF(birthdate, '1967-03-03 15:06:36') <= 0 ORDER BY last_active DESC LIMIT 100 

我認爲原因執行時間較長的是,它有這樣做的查詢,因此我嘗試這種方法之前加入與其他表的整個用戶表:

SELECT iduser, imageurl, birthdate, active, last_active, created, gender_idgender, orientation_idorientation, region_idregion, moji.moji_idmoji as moji_idmoji, status.value as status, requests.value as requestsRecv, requestssent.value as requestsSent, username.value as username, likecount.value as likeCount, reportcount.value as reportCount 
FROM (SELECT * FROM user WHERE banned = 0 AND active = 1 AND reviewstatus_idreviewstatus = 3 AND DATEDIFF(last_active,'2017-03-03 10:01:30') >=0 AND DATEDIFF(birthdate, '1999-03-03 15:01:30') >= 0 AND DATEDIFF(birthdate, '1967-03-03 15:01:30') <= 0 ORDER BY last_active DESC LIMIT 100) as u 
    JOIN user_has_moji moji ON (u.iduser = moji.user_iduser) 
    JOIN user_has_data status ON (u.iduser = status.user_iduser AND status.datatype_iddatatype = 1) 
    JOIN user_has_data requests ON (u.iduser = requests.user_iduser AND requests.datatype_iddatatype = 3) 
    JOIN user_has_data requestssent ON (u.iduser = requestssent.user_iduser AND requestssent.datatype_iddatatype = 4) 
    JOIN user_has_data username ON (u.iduser = username.user_iduser AND username.datatype_iddatatype = 5) 
    JOIN user_has_data likecount ON (u.iduser = likecount.user_iduser AND likecount.datatype_iddatatype = 6) 
    JOIN user_has_data reportcount ON (u.iduser = reportcount.user_iduser AND reportcount.datatype_iddatatype = 7) 

想想需要連接的行數會大大減少,因此會縮短執行時間。這種改變似乎有所幫助,但查詢仍然太低。

有人可以看到執行緩慢的一些其他原因嗎?

+2

似乎是一個合理的響應時間... – jarlh

+1

查詢似乎固定,建議索引改進... – JohnHC

回答

3

你有一個非常合理的響應時間,所以你的表似乎是正確的索引。但是,讓我們看看WHERE條款(我加的是假定表的別名):

WHERE u.banned = 0 AND u.active = 1 AND 
     u.reviewstatus_idreviewstatus = 3 AND 
     DATEDIFF(u.last_active,'2017-03-03 10:06:36') >=0 AND 
     DATEDIFF(u.birthdate, '1999-03-03 15:06:36') >= 0 AND 
     DATEDIFF(u.birthdate, '1967-03-03 15:06:36') <= 0 

首先,刪除datediff()並做簡單的比較。我想你想要這樣的:

WHERE u.banned = 0 AND u.active = 1 AND 
     u.reviewstatus_idreviewstatus = 3 AND 
     u.last_active >= '2017-03-03 10:06:36' AND 
     u.birthdate >= '1999-03-03 15:06:36' AND 
     u.birthdate <= '1967-03-03 15:06:36' 

我有點懷疑,最後的三個條件,但使用datediff()是混亂的。這是簡單比較更好的原因之一。

您需要快速找到這些行,這表明兩個指標之一:

users(banned, active, reviewstatus_idreviewstatus, last_active, birthdate) 

users(banned, active, reviewstatus_idreviewstatus, birthdate, last_active) 

這取決於其whittles下來的數據更多。我的猜測是last_active更重要。還要注意,前三個鍵可以按任意順序排列,只要它們是前三個。

這可能有幫助,但我懷疑你會看到一個驚人的進步。

+0

感謝acutally確實有點幫助:) –

+0

快多少? –

+0

100-200毫秒更快 –