2017-11-25 227 views
1

我有兩個表:MySQL右加慢性能

餐廳和SurveyInvitation。

一家餐廳有很多調查邀請。

我想選擇所有有調查邀請的餐廳,並且它的狀態是「已批准」,「已完成」,「hidden_​​review」。

餐廳的餐桌有1400行,調查邀請~240萬行。

這是我的查詢

SELECT `Restaurant`.`id` 
FROM `restaurants` AS `Restaurant` 
RIGHT JOIN `survey_invitations` AS `SurveyInvitations` 
      ON (`SurveyInvitations`.`restaurant_id` = `Restaurant`.`id` 
       AND `SurveyInvitations`.`status` 
       IN (
        'approved', 'completed', 'hidden_review' 
        ) 
       ) 
WHERE `Restaurant`.`country_id` = 53 
AND `Restaurant`.`area_id` IN (1, 16, 27, 118, 
            219, 221, 222, 223, 
            224, 225, 230, 231, 
            235, 236, 237, 238, 
            239, 240, 248, 226, 
            241, 244, 246, 227, 
            245, 228, 229, 242, 
            243, 249) 

group by `Restaurant`.`id` 

這個運行在1.235秒。

運行解釋給

https://jsfiddle.net/bjuepb9j/3

我也試過,但沒有運氣還是1.2秒

SELECT `Restaurant`.`id` 
FROM `db_portal`.`restaurants` AS `Restaurant` 
RIGHT JOIN (
    select `restaurant_id` from `survey_invitations` AS `SurveyInvitations` 
    where `SurveyInvitations`.`status` 
    IN ('approved', 'hidden_review', 'completed') 
) AS `SurveyInvitations` 
ON (
`SurveyInvitations`.`restaurant_id` = `Restaurant`.`id` 
) 
WHERE `Restaurant`.`country_id` = 53 
AND `Restaurant`.`area_id` IN (1, 16, 27, 118, 
            219, 221, 222, 223, 
            224, 225, 230, 231, 
            235, 236, 237, 238, 
            239, 240, 248, 226, 
            241, 244, 246, 227, 
            245, 228, 229, 242, 
            243, 249) 

group by `Restaurant`.`id` 

解釋是一樣的。

在小提琴中也有來自兩個表上的顯示索引的結果。

約2.4萬行1.2秒是我想。 也許索引是錯的,我不擅長這類東西。

Edit.1。 https://jsfiddle.net/bjuepb9j/6/

有節目製作survey_invitations

+0

你可以分享你的表創建帶有索引的語句和(主/唯一鍵)? –

+0

你爲什麼使用'RIGHT JOIN'?使用正確的連接,右側連接標準中的表將永遠不會爲null(因爲null不等於null),這意味着「餐廳」表是可選的,但是您可以通過做在否定條件對「Restaraunts」表(country_id和area_id)進行平等檢查。我認爲內連接會更簡單。試試看看它是如何影響性能的。 (內連接提供更多優化選項) – Brandon

回答

1

使用exists表並顯示列:

SELECT r.id 
FROM restaurants r 
WHERE r.country_id = 53 AND 
     r.area_id IN (1, 16, 27, 118, 219, 221, 222, 223, 
        224, 225, 230, 231, 235, 236, 237, 238, 
        239, 240, 248, 226, 241, 244, 246, 227, 
        245, 228, 229, 242, 243, 249 
        ) AND 
     EXISTS (SELECT 1 
       FROM survey_invitations si 
       WHERE si.restaurant_id = r.id AND 
        si.status IN ('approved', 'completed', 'hidden_review') 
      ); 

然後,這個查詢你想在restaurants(country_id, area_id, id)survey_invitations(restaurant_id, status)指標。

A right join對於您的查詢完全不需要。無論如何,where條款將其變爲inner join。很有可能,查詢的費用在group by。這個版本消除了這一點。

+0

在0.6秒內工作。 並感謝存在,是我不需要數據的方式。 –

1

我建議用IN子查詢替換連接,而不是EXISTS子查詢。 使用IN子查詢編寫查詢時,可避免相關的EXISTS查詢,該查詢偶爾會較慢(取決於結果數量)。 試試這個:

SELECT 
     r.id 
    FROM 
     restaurants r 
    WHERE 
     r.country_id = 53 
     AND r.area_id IN (
      1, 16, 27, 118, 219, 221, 222, 223, 224, 225, 230, 231, 235, 236, 237, 238, 239, 240, 248, 226, 241, 244, 246, 227, 245, 228, 229, 242, 243, 249 
     ) 
     AND r.id IN (
      (
       SELECT 
        si.restaurant_id 
       FROM 
        survey_invitations si 
       WHERE 
        1 = 1 
        AND si.status IN (
         'approved', 'completed', 'hidden_review' 
        ) 
      ) 
     ) 

對於此查詢,添加這些索引:

ALTER TABLE `restaurants` ADD INDEX `restaurants_index_1` (`country_id`, `area_id`, `id`); 
ALTER TABLE `survey_invitations` ADD INDEX `survey_invitations_index_1` (`restaurant_id`, `status`);