2012-12-25 89 views
4

我正在執行JOIN從多個表執行分面搜索。當避免JOIN並將查詢分成兩個不同的查詢時,我注意到一個很大的性能提升,所以我假設我的JOIN沒有被優化。什麼會導致連接比分爲兩個查詢慢?

結構:

-- tags 
userId | tagId 
1    3 
1    4 
2    3 
2    9 

-- search 
userId | number | countryId | stateId ... 
1    13   221    55 

-- countries 
countryId  | countryName 
221     Somewhere 

-- users 
userId | profileImageLink 
1   | <photo link> 

我試圖提取有標籤的所有用戶,按照search.number和其他表把元數據的順序。查詢:

SELECT 
    search.*, users.a, users.b, users.c, users.d, users.e, users.f, countries.location_country, states.location_state, cities.location_city 
FROM search 
RIGHT JOIN tags 
    ON search.user_id = tags.user_id 
LEFT JOIN users 
    ON users.user_id=search.user_id 
LEFT JOIN countries 
    ON countries.countryId=search.countryId 
LEFT JOIN states 
    ON states.countryId=search.countryId AND states.stateId=search.stateId 
LEFT JOIN cities 
    ON cities.countryId=search.countryId AND cities.stateId=search.stateId AND cities.cityId=search.cityId 
WHERE 
    tags.skillId =52772 
ORDER BY 
    search.number DESC LIMIT 0,200 

我注意到刪除JOIN到用戶表(並做了之後)使查詢快得多。我如何優化它以在相同的查詢中工作?我試着改變FROM到標籤,而不是搜索,但沒有奏效...

這是EXPLAIN顯示:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE tags ref skill_user,skillId skill_user 4 const 184854 Using index; Using temporary; Using filesort 
1 SIMPLE search eq_ref user_id user_id 4 tags.user_id 1 
1 SIMPLE countries eq_ref PRIMARY PRIMARY 2 search.countryId 1 
1 SIMPLE states eq_ref PRIMARY,state PRIMARY 3 search.stateId 1 
1 SIMPLE cities eq_ref PRIMARY,city PRIMARY 3 search.cityId 1 
1 SIMPLE users eq_ref user_id user_id 4 search.user_id 1 

EXPLAIN without the LEFT JOIN users: 

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE tags ref skill_user,skillId skill_user 4 const 155870 Using index 
1 SIMPLE search eq_ref user_id user_id 4 tags.user_id 1 
1 SIMPLE countries eq_ref PRIMARY PRIMARY 2 search.countryId 1 
1 SIMPLE states eq_ref PRIMARY,state PRIMARY 3 search.stateId 1 
1 SIMPLE cities eq_ref PRIMARY,city PRIMARY 3 search.cityId 1 

EXPLAIN查詢的建議回答:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE tags index NULL userid_skill 8 NULL 22689539 Using where; Using index; Using temporary; Using filesort 
1 SIMPLE search eq_ref user_id user_id 4 tags.user_id 1 
1 SIMPLE users eq_ref user_id user_id 4 search.user_id 1 
1 SIMPLE countries eq_ref PRIMARY PRIMARY 2 search.countryId 1 
1 SIMPLE states eq_ref PRIMARY,state PRIMARY 3 search.stateId 1 
1 SIMPLE cities eq_ref PRIMARY,city PRIMARY 3 search.cityId 1 
+1

是你的列(在加入柱)正確索引?非物質的,我建議避免這麼多的聯接。我認爲當你的數據量有可能增長時,分解查詢是一個更好的主意。 –

+0

索引你的連接列,也許where子句中的where列...不知道我建議的建議是 –

+1

你可以發佈你的查詢的「解釋」結果嗎?只需在查詢前添加EXPLAIN關鍵字 – sdespont

回答

2

創建上表的索引運行以下查詢:

Table ColumnName 
------ ---------- 
tags  user_id, skillid (Both column in one index) 

試試這個:

SELECT s.*, u.a, u.b, u.c, u.d, u.e, u.f, c.location_country, 
     st.location_state, ct.location_city 
FROM tags t 
LEFT JOIN search s ON t.user_id = s.user_id 
LEFT JOIN users u ON t.user_id = u.user_id 
LEFT JOIN countries c ON s.countryId = c.countryId 
LEFT JOIN states st ON s.stateId = st.stateId 
LEFT JOIN cities ci ON s.cityId= ct.cityId 
WHERE t.skillId =52772 
ORDER BY s.number DESC 
LIMIT 0,200 

編輯

嘗試用適當的指數這兩個查詢,讓我知道,下面的查詢是爲您或不工作。

SELECT s.*, u.a, u.b, u.c, u.d, u.e, u.f, c.location_country, 
     st.location_state, ct.location_city 
FROM (SELECT user_id FROM tags WHERE t.skillId = 52772) AS t 
LEFT JOIN search s ON t.user_id = s.user_id 
LEFT JOIN users u ON t.user_id = u.user_id 
LEFT JOIN countries c ON s.countryId = c.countryId 
LEFT JOIN states st ON s.stateId = st.stateId 
LEFT JOIN cities ci ON s.cityId= ct.cityId 
ORDER BY s.number DESC 
LIMIT 0,200; 

OR

SELECT s.*, u.a, u.b, u.c, u.d, u.e, u.f, c.location_country, 
     st.location_state, ct.location_city 
FROM (SELECT t.user_id, s.* FROM tags t 
     LEFT JOIN search s ON t.user_id = s.user_id 
     WHERE t.skillId = 52772 
     ORDER BY s.number DESC 
     LIMIT 0,200) AS t 
LEFT JOIN users u ON t.user_id = u.user_id 
LEFT JOIN countries c ON s.countryId = c.countryId 
LEFT JOIN states st ON s.stateId = st.stateId 
LEFT JOIN cities ci ON s.cityId= ct.cityId 
ORDER BY s.number DESC 
LIMIT 0,200; 
+0

當您運行查詢時,上傳您的EXPLAIN語句的輸出,因此我可以理解它的工作原理而不是 –

+0

這是我一開始想的(改變FROM),但它仍然是一樣的。我再次運行它以確保,並且解釋也顯示了相同的情況。並且,儘管存在兩個列,但他不使用兩列的索引 – Noam

+0

按user_id和skillid的順序在兩列上創建合併索引。並在查詢中使用該索引作爲** LEFT JOIN搜索s USE INDEX(index_1)ON t.user_id = s.user_id **。並更新我的相同。 –

相關問題