2013-10-10 67 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