MySQL正确加入缓慢的性能

时间:2017-11-25 17:14:26

标签: performance indexing mysql-5.7 right-join

我有两张桌子:

餐馆和SurveyInvitation。

一家餐馆有很多调查邀请。

我想选择所有有调查邀请的餐厅,并且其状态已经过批准','已完成'隐藏的查看'

餐馆餐桌有大约1400行,调查邀请大约有2.4万行。

这是我的查询

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`

解释是一样的。

在小提琴中,两个表上的show index也有结果。

对于大约240万行,我认为1.2秒。 也许索引是错的,我对这种东西并不擅长。

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

show show table并显示survey_invitations的列

2 个答案:

答案 0 :(得分: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)上的索引。

您的查询完全不需要right join。无论如何where子句将其转换为inner join。很有可能,查询的费用在group by。这个版本消除了这一点。

答案 1 :(得分: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`);