2013-09-24 38 views
1

我有一個非常長的選擇從MySQL數據庫。它工作得很快,直到我加入了這個INNER JOIN。在我加入這個INNER JOIN選擇時間爲2秒,現在則是20秒左右......更快的等效的mysql內部連接總和

INNER JOIN 
    (SELECT 
     accomodation_id, 
     SUM(accomodation_rooms.rooms) AS total_rooms, 
     SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons 

    FROM accomodation_rooms 

    GROUP BY accomodation_id) accomodation_rooms 

ON 
    accomodation_rooms.accomodation_id = accomodation.id 
    AND 
    accomodation_rooms.total_persons >= '".$persons."' 

有人可以幫助我做一些更快的替代方案?

+1

請發佈您的完整查詢不是它的一部分 –

+0

好吧,你想要它:)檢查我的帖子 – general666

+0

運行解釋這部分和發佈結果:'EXPLAIN SELECT accomodation_id,SUM(accomodation_rooms.rooms)AS total_rooms,SUM(accomodation_rooms.beds * accomodation_rooms.rooms)AS total_persons FROM accomodation_rooms GROUP BY accomodation_id'你有關於accomodation_id和rooms的索引嗎? –

回答

0
SELECT 
    accomodation.id, 
    accomodation.aid, 
    accomodation.title_en, 
    accomodation.title_url_en, 
    accomodation.address, 
    accomodation.zip, 
    accomodation.stars, 
    accomodation.picture, 
    accomodation.valid_from, 
    accomodation.valid_to, 
    accomodation.latitude, 
    accomodation.longitude, 
    accomodation.city_id AS accomodation_city_id, 
    db_cities.id AS city_id, 
    db_cities.title_en AS city, 
    db_cities.title_url AS city_url, 
    db_countries.title_en AS country_title, 
    db_countries.title_url_en AS country_url, 
    accomodation_type.class AS accomodation_type_class, 
    accomodation_review_value_total.value AS review_total, 
    MIN(accomodation_price.price) AS price_from, 
    accomodation_rooms.total_persons 
FROM 
    (SELECT aid, MAX(info_date_add) AS max_info_date_add FROM accomodation GROUP BY aid) accomodation_max 
INNER JOIN accomodation 
    ON 
     accomodation_max.aid = accomodation.aid AND 
     accomodation_max.max_info_date_add = accomodation.info_date_add 
LEFT JOIN db_cities 
    ON 
     (db_cities.id = accomodation.city_id OR (((acos(sin((db_cities.latitude*pi()/180)) * sin((accomodation.latitude*pi()/180)) + cos((db_cities.latitude*pi()/180)) * cos((accomodation.latitude*pi()/180)) * cos(((db_cities.longitude - accomodation.longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344) < '20') 
JOIN db_countries 
    ON db_countries.id = accomodation.country_id 
LEFT JOIN accomodation_review_value_total 
    ON accomodation_review_value_total.accomodation_aid = accomodation.aid 
LEFT JOIN accomodation_type_value 
    ON accomodation_type_value.accomodation_id = accomodation.id 
LEFT JOIN accomodation_type 
    ON accomodation_type.id = accomodation_type_value.accomodation_type_id 
LEFT JOIN accomodation_price 
    ON 
     (accomodation_price.accomodation_aid = accomodation.aid AND 
     accomodation_price.accomodation_price_type_id = '1' AND 
     accomodation_price.accomodation_price_cat_id = '1') 
LEFT JOIN accomodation_season 
    ON 
     (accomodation_season.accomodation_aid = accomodation.aid AND 
     accomodation_season.id = accomodation_price.accomodation_season_id AND 
     ('2013-09-25' >= accomodation_season.start_date AND 
     accomodation_season.end_date >= '2013-09-25' OR '2013-09-26' >= accomodation_season.start_date AND 
     accomodation_season.end_date >= '2013-09-26')) 
INNER JOIN 
     (SELECT accomodation_id, SUM(accomodation_rooms.rooms) AS total_rooms, 
     SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons 
    FROM accomodation_rooms 
    GROUP BY accomodation_id) accomodation_rooms 
ON 
    accomodation_rooms.accomodation_id = accomodation.id AND 
    accomodation_rooms.total_persons >= '4' 
WHERE 
    db_countries.title_url_en LIKE '%country%' AND 
    db_cities.title_url LIKE '%city%' AND 
    total_rooms >= '2' AND 
    db_cities.id = '2416' 
GROUP BY accomodation.aid 
ORDER BY CASE 
    WHEN 
     accomodation.valid_to>=NOW() AND 
     accomodation.valid_from<=NOW() THEN 0 
    WHEN 
     NOW()>accomodation.valid_to AND 
     accomodation.valid_to!='0000-00-00' THEN 1 ELSE 2 END, 
review_total DESC, accomodation.title_en LIMIT 10 OFFSET 0 
+0

這個查詢應該是什麼?這是對原始問題的回答嗎?一個簡短的描述將很好,使其對其他人有用。 – Michael

0

我修改了你的查詢,刪除了多餘的連接並將它們組合起來試試這個。

SELECT 
    accomodation.id, 
    accomodation.aid, 
    accomodation.title_en, 
    accomodation.title_url_en, 
    accomodation.address, 
    accomodation.zip, 
    accomodation.stars, 
    accomodation.picture, 
    accomodation.valid_from, 
    accomodation.valid_to, 
    accomodation.latitude, 
    accomodation.longitude, 
    MAX(info_date_add)     AS max_info_date_add, 
    accomodation.city_id     AS accomodation_city_id, 
    db_cities.id       AS city_id, 
    db_cities.title_en     AS city, 
    db_cities.title_url     AS city_url, 
    db_countries.title_en     AS country_title, 
    db_countries.title_url_en    AS country_url, 
    accomodation_type.class    AS accomodation_type_class, 
    accomodation_review_value_total.value AS review_total, 
    MIN(accomodation_price.price)   AS price_from, 
    accomodation_rooms.total_persons, 
    (((acos(sin((db_cities.latitude * pi()/180)) * sin((accomodation.latitude * pi()/180)) + cos((db_cities.latitude * pi()/180)) * cos((accomodation.latitude * pi()/180)) * cos(((db_cities.longitude - accomodation.longitude) * pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.609344) as Calculation 
FROM accomodation 
LEFT JOIN db_cities ON db_cities.id = accomodation.city_id 
LEFT JOIN db_countries ON db_countries.id = accomodation.country_id 
LEFT JOIN accomodation_review_value_total ON accomodation_review_value_total.accomodation_aid = accomodation.aid 
LEFT JOIN accomodation_price ON (accomodation_price.accomodation_aid = accomodation.aid AND accomodation_price.accomodation_price_type_id = '1' AND accomodation_price.accomodation_price_cat_id = '1') 
INNER JOIN (SELECT 
       accomodation_id, 
       SUM(accomodation_rooms.rooms)   AS total_rooms, 
       SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons 
       FROM accomodation_rooms 
       GROUP BY accomodation_id) accomodation_rooms 
    ON accomodation_rooms.accomodation_id = accomodation.id 
     AND accomodation_rooms.total_persons >= '4' 
WHERE db_countries.title_url_en LIKE '%country%' 
    AND db_cities.title_url LIKE '%city%' 
    AND total_rooms >= '2' 
    AND db_cities.id = '2416' 
GROUP BY accomodation.aid 
HAVING Calculation < 20 
ORDER BY CASE WHEN accomodation.valid_to >= NOW() 
    AND accomodation.valid_from <= NOW()THEN 0 WHEN NOW() > accomodation.valid_to 
    AND accomodation.valid_to != '0000-00-00'THEN 1 ELSE 2 END, review_total DESC, accomodation.title_en 
LIMIT 10 OFFSET 0 

EDITS:

你仍然可以使用自己在這裏加入

SELECT 
    accomodation.id, 
    accomodation.aid, 
    accomodation.title_en, 
    accomodation.title_url_en, 
    accomodation.address, 
    accomodation.zip, 
    accomodation.stars, 
    accomodation.picture, 
    accomodation.valid_from, 
    accomodation.valid_to, 
    accomodation.latitude, 
    accomodation.longitude, 
    MAX(info_date_add)     AS max_info_date_add, 
    accomodation.city_id     AS accomodation_city_id, 
    db_cities.id       AS city_id, 
    db_cities.title_en     AS city, 
    db_cities.title_url     AS city_url, 
    db_countries.title_en     AS country_title, 
    db_countries.title_url_en    AS country_url, 
    accomodation_type.class    AS accomodation_type_class, 
    accomodation_review_value_total.value AS review_total, 
    MIN(accomodation_price.price)   AS price_from, 
    accomodation_rooms.total_persons, 
    SUM(IFNULL(accomodation_rooms.rooms,0,1)) AS total_rooms, 
    SUM(IFNULL(accomodation_rooms.beds * accomodation_rooms.rooms,0,1)) AS total_persons 
FROM accomodation 
    LEFT JOIN db_cities 
    ON db_cities.id = accomodation.city_id 
    LEFT JOIN db_countries 
    ON (db_cities.id = accomodation.city_id 
     OR (((acos(sin((db_cities.latitude * pi()/180)) * sin((accomodation.latitude * pi()/180)) + cos((db_cities.latitude * pi()/180)) * cos((accomodation.latitude * pi()/180)) * cos(((db_cities.longitude - accomodation.longitude) * pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.609344) < '20') 
    LEFT JOIN accomodation_review_value_total 
    ON accomodation_review_value_total.accomodation_aid = accomodation.aid 
    LEFT JOIN accomodation_price 
    ON (accomodation_price.accomodation_aid = accomodation.aid 
     AND accomodation_price.accomodation_price_type_id = '1' 
     AND accomodation_price.accomodation_price_cat_id = '1') 
    LEFT JOIN accomodation_rooms 
    ON accomodation_rooms.accomodation_id = accomodation.id 
WHERE db_countries.title_url_en LIKE '%country%' 
    AND db_cities.title_url LIKE '%city%' 
    AND total_rooms >= '2' 
    AND db_cities.id = '2416' 
GROUP BY accomodation.aid 
HAVING accomodation_rooms.total_persons >= '4' 
ORDER BY CASE WHEN accomodation.valid_to >= NOW() 
    AND accomodation.valid_from <= NOW()THEN 0 WHEN NOW() > accomodation.valid_to 
    AND accomodation.valid_to != '0000-00-00'THEN 1 ELSE 2 END, review_total DESC, accomodation.title_en 
LIMIT 10 OFFSET 0 

安大略省東西的方式是,你可以使用左連接,而不是內部聯接我想這會更快。把條件放在HAVAING子句中。另外請注意我正在申請IF條件,同時選擇如此,如果空來它將總結0其他1.

+0

嗯,它看起來真的更快,當我選擇計算,然後我使用有。但是我還有一個問題。我如何修改它以顯示也沒有指定緯度和經度的結果,因此計算不可用?在我的選擇中,在JOIN db_cities上有2個條件 - 按ID或DISTANCE – general666

+0

可以將條件放在子句中。 '計算<20或計算IS NULL'。我猜NULL只會在計算不可用時纔會出現 –

+0

確定它正在工作,但我沒有注意到另外一個問題...現在它只連接表db_cities ON ID,但我還需要按距離連接城市... – general666