2017-11-25 230 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`);