2012-10-27 53 views
1

儘管我正在開發一個大型Web應用程序,但我還沒有很多MySQL和數據庫方面的經驗。以下是我的應用的搜索查詢,它允許用戶搜索其他用戶。現在,此查詢dev_Profile的主表具有大約14K行,查詢速度相當慢(運行查詢時會返回最大集合大約5秒)。我確定這裏可以做許多優化調整,但是創建索引是這裏要做的最基本的第一步?我一直試圖自己學習索引,以及如何爲具有多個連接的查詢創建索引,但我只是不太明白。我希望在我的實際查詢中看到事物可能更具教育意義。試圖爲MySQL查詢創建索引

這裏的基本查詢:

SELECT 
    dev_Profile.ID AS pid, 
    dev_Profile.Name AS username, 
    IF(TIMESTAMPDIFF(SECOND, st1.lastActivityTime, UTC_TIMESTAMP()) > 300 OR ISNULL(TIMESTAMPDIFF(SECOND, st1.lastActivityTime, UTC_TIMESTAMP())), 0, 1) AS online, 
    FLOOR(DATEDIFF(CURRENT_DATE, dev_Profile.DOB)/365) AS age, 
    IF(dev_Profile.GenderID=1, 'M', 'F') AS sex, 
    IF(ISNULL(st2.Description), 0, st2.Description) AS relStatus, 
    st3.Name AS country, 
    IF(dev_Profile.RegionID > 0, st4.Name, 0) AS region, 
    IF(dev_Profile.CityID > 0, st5.Name, 0) AS city, 
    IF(ISNULL(st6.filename), 0, IF(st6.isApproved=1 AND st6.isDiscarded=0 AND st6.isModerated=1 AND st6.isRejected=0 AND isSizeAvatar=1, 1, 0)) AS hasPhoto, 
    IF(ISNULL(st6.filename), IF(dev_Profile.GenderID=1, 'http://www.mysite.com/lib/images/avatar-male-small.png', 'http://www.mysite.com/lib/images/avatar-female-small.png'), IF(st6.isApproved=1 AND st6.isDiscarded=0 AND st6.isModerated=1 AND st6.isRejected=0 AND isSizeAvatar=1, CONCAT('http://www.mysite.com/uploads/', st6.filename), IF(dev_Profile.GenderID=1, 'http://www.mysite.com/lib/images/avatar-male-small.png', 'http://www.mysite.com/lib/images/avatar-female-small.png'))) AS photo, 
    IF(ISNULL(dev_Profile.StatusMessage), IF(ISNULL(dev_Profile.AboutMe), IF(ISNULL(st7.AboutMyMatch), 0, st7.AboutMyMatch), dev_Profile.AboutMe), dev_Profile.StatusMessage) AS text 
FROM 
    dev_Profile 
    LEFT JOIN dev_User AS st1 ON st1.ID = dev_Profile.UserID 
    LEFT JOIN dev_ProfileRelationshipStatus AS st2 ON st2.ID = dev_Profile.ProfileRelationshipStatusID 
    LEFT JOIN Country AS st3 ON st3.ID = dev_Profile.CountryID 
    LEFT JOIN Region AS st4 ON st4.ID = dev_Profile.RegionID 
    LEFT JOIN City AS st5 ON st5.ID = dev_Profile.CityID 
    LEFT JOIN dev_Photos AS st6 ON st6.ID = dev_Profile.PhotoAvatarID 
    LEFT JOIN dev_DesiredMatch AS st7 ON st7.ProfileID = dev_Profile.ID 
WHERE 
    dev_Profile.ID != 11222 /* $_SESSION['ProfileID'] */ 
    AND st1.EmailVerified = 'true' 
    AND st1.accountIsActive=1 
ORDER BY st1.lastActivityTime DESC LIMIT 900; 

此查詢的速度(太慢了,你可以看到):

900 rows in set (5.20 sec) 

的解釋此查詢:

+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key  | key_len | ref           | rows | Extra          | 
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+ 
| 1 | SIMPLE  | dev_Profile | range | PRIMARY  | PRIMARY | 4  | NULL          | 13503 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | st2   | eq_ref | PRIMARY  | PRIMARY | 1  | syk.dev_Profile.ProfileRelationshipStatusID |  1 |            | 
| 1 | SIMPLE  | st3   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.CountryID     |  1 |            | 
| 1 | SIMPLE  | st4   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.RegionID     |  1 |            | 
| 1 | SIMPLE  | st5   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.CityID      |  1 |            | 
| 1 | SIMPLE  | st1   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.UserID      |  1 | Using where         | 
| 1 | SIMPLE  | st6   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.PhotoAvatarID    |  1 |            | 
| 1 | SIMPLE  | st7   | ALL | NULL   | NULL | NULL | NULL          | 442 |            | 
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+ 

查詢可能還有更多WHEREHAVING子句,如果用戶搜索包含其他條件。附加子句(設定示例值):

AND dev_Profile.GenderID = 1 
AND dev_Profile.CountryID=127 
AND dev_Profile.RegionID=36 
AND dev_Profile.CityID=601 
HAVING (age >= 18 AND age <= 50) 
AND online=1 
AND hasPhoto=1 

這是利用一切可能WHEREHAVING條款的解釋查詢:

+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key  | key_len | ref           | rows | Extra          | 
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+ 
| 1 | SIMPLE  | dev_Profile | range | PRIMARY  | PRIMARY | 4  | NULL          | 13503 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | st2   | eq_ref | PRIMARY  | PRIMARY | 1  | syk.dev_Profile.ProfileRelationshipStatusID |  1 |            | 
| 1 | SIMPLE  | st3   | const | PRIMARY  | PRIMARY | 4  | const          |  1 |            | 
| 1 | SIMPLE  | st4   | const | PRIMARY  | PRIMARY | 4  | const          |  1 |            | 
| 1 | SIMPLE  | st5   | const | PRIMARY  | PRIMARY | 4  | const          |  1 |            | 
| 1 | SIMPLE  | st1   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.UserID      |  1 | Using where         | 
| 1 | SIMPLE  | st6   | eq_ref | PRIMARY  | PRIMARY | 4  | syk.dev_Profile.PhotoAvatarID    |  1 |            | 
| 1 | SIMPLE  | st7   | ALL | NULL   | NULL | NULL | NULL          | 442 |            | 
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+ 

我甚至不知道這是TMI還是不夠。

索引是採取正確的措施嗎?如果是這樣,有人能讓我朝着正確的方向前進嗎?

+0

它看起來好像你有外鍵設置,這是很好的:)另一個索引表將'st1'我相信'(lastActivityTime,emailVerified,accountIsActive)'。 –

回答

1

正確的一步是加快您的查詢速度!

用你原來的查詢,我會說你最終在dev_Profile表上做表掃描,因爲它沒有可索引條件。使用修改後的查詢,它取決於列中允許的不同值的數量 - 如果有可能重複,則索引可能無法使用,因爲無論如何它必須獲取表以完成查詢的其餘部分。

我已經正確地閱讀了您的計劃,然後您已經將所有其他表加入已索引的不可爲空的列(除了st7,由於某種原因似乎沒有使用索引)。因此它看起來好像你不應該使用左連接。這將允許在表st1上使用(EmailVerified, accountIsActive, lastActivityTime)上的索引。

0

應該使用與頻繁查詢相關的索引。一個索引稍微降低了寫入性能,同時極大地提高了搜索速度。作爲一個經驗法則,對象自己的ID應該作爲PRIMARY鍵索引,並且在查詢中總是出現一個列組的索引是一個好主意。我想你應該索引GenderID,CountryID,RegionID,CityID,年齡,在線和hasPhoto。如果您認爲沒有使用正確的索引,則應該至少提供dev_Profile的模式。

請注意,國家/地區/城市ID可能代表冗餘信息。您的設計可能不夠理想。

注意2:你在SELECT中做了很多應用程序邏輯。 SQL不是爲這些大量的IF-in-IF-in-IF子句設計的,而且由於URL的查詢返回的表格比如果你剛剛請求相關字段(例如文件名,genderID等等上)。可能有時候查詢必須返回這些精確的解釋值,一般而言,您最好(在速度和可讀性方面)將這些處理步驟編碼到您的應用程序代碼中。