2013-10-10 103 views
1

我有一個非常複雜的查詢正在運行,查找成員加入訂閱詳細信息和按距離排序的位置。複雜的MySQL選擇左連接優化索引

有人可以提供有關正確索引和基數的指示,我應該添加以加快此加載速度。

現在在100萬條記錄上需要75秒,我知道它可以改進。

謝謝。

SELECT SQL_CALC_FOUND_ROWS (((acos(sin((33.987541*pi()/180)) * sin((users_data.lat*pi()/180))+cos((33.987541*pi()/180)) * cos((users_data.lat*pi()/180)) * cos(((-118.472153- users_data.lon)* pi()/180))))*180/pi())*60*1.1515) as distance,subscription_types.location_limit as location_limit,users_data.user_id,users_data.last_name,users_data.filename,users_data.user_id,users_data.phone_number,users_data.city,users_data.state_code,users_data.zip_code,users_data.country_code,users_data.quote,users_data.subscription_id,users_data.company,users_data.position,users_data.profession_id,users_data.experience,users_data.account_type,users_data.verified,users_data.nationwide,IF(listing_type = 'Company', company, last_name) as name 
FROM `users_data` 
LEFT JOIN `users_reviews` ON users_data.user_id=users_reviews.user_id AND users_reviews.review_status='2' 
LEFT JOIN users_locations ON users_locations.user_id=users_data.user_id 
LEFT JOIN subscription_types ON users_data.subscription_id=subscription_types.subscription_id 
WHERE users_data.active='2' 
AND subscription_types.searchable='1' 
AND users_data.state_code='CA' 
AND users_data.country_code='US' 
GROUP BY users_data.user_id 
HAVING distance <= '50' 
OR location_limit='all' 
OR users_data.nationwide='1' 
ORDER BY subscription_types.search_priority ASC, distance ASC 
LIMIT 0,10 

EXPLAIN

ID SELECT_TYPE表型possible_keys鍵key_len REF行額外
1 SIMPLE users_reviews系統USER_ID,review_status NULL NULL NULL 0常量行沒有找到 1 SIMPLE users_locations系統USER_ID NULL NULL NULL 0 const row not found 1 SIMPLE users_data ref subscription_id,active,state_code,country_code state_code 47 const 88241 Using where;使用臨時;使用filesort 1 SIMPLE subscription_types ALL PRIMARY,可搜索的NULL NULL NULL 4使用where;使用加入緩衝區

+0

如果它不經常改變,你可以緩存結果,只要有人更新了某些東西,就運行查詢並緩存新的出來。 –

+0

你爲什麼強制索引爲'(users_data.lat,users_data.lon)'?這些列不在JOIN或WHERE中使用。 – Barmar

+0

嘗試使用INNER JOIN而不是LEFT JOIN。它看起來不像你想要的不匹配的行,因爲你在'WHERE'子句中指定了'subscription_types.searchable'。 – Barmar

回答

2

您的查詢不是那麼複雜。你只有一個加入,在桌子subscription_types這當然是一個不超過幾百行的小桌子。

  • 您的索引在哪裏?以提高查詢的最好方法是創建要篩選的字段索引,像activecountry_codestate_codesearchable
  • 你創建users_data.subscription_id外鍵?你也需要一個索引。
  • ForceIndex沒用,讓RDBMS確定選擇的最佳索引。
  • 左聯接是太沒用,因爲線subscription_types.searchable='1'將刪除的不匹配對應關係
  • 順序上search_priority意味着你需要指數在此列太
  • HAVING過濾可以使不使用索引。您無需將這些過濾器放入HAVING。如果我理解你的表模式,這不是真正的被過濾的聚合。

你的表包含100萬行,但是返回多少行,沒有限制?使用正確的索引,查詢應該在一秒鐘內執行。

SELECT ... 
FROM `users_data` 
    INNER JOIN subscription_types 
     ON users_data.subscription_id = subscription_types.subscription_id 
WHERE users_data.active='2' 
    AND users_data.country_code='US' 
    AND users_data.state_code='NY' 
    AND subscription_types.searchable='1' 
    AND (distance <= '50' OR location_limit='all' OR users_data.nationwide='1') 
GROUP BY users_data.user_id 
ORDER BY subscription_types.search_priority ASC, distance ASC 
LIMIT 0,10 
+0

+1但我不同意你關於「ForceIndex是無用的」...它是非常有用的,如果你的索引基數不是最新的,RDMS選擇一個較弱的索引,或者甚至選擇不使用索引 – Stephan

+0

我認爲99.9%的查詢不需要你指定如何使用索引。它可能發生,但首先證明我是執行計劃! –

+0

我同意爲了做出這樣的決定,你需要首先看到'EXPLAIN'輸出 – Stephan