MySQL正确加入缓慢的性能

问题描述 投票:1回答:2

我有两张桌子:

餐馆和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`

解释是一样的。

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

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

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

已显示创建表并显示survey_invitations列

performance indexing mysql-5.7 right-join
2个回答
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
投票

我建议用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`);
© www.soinside.com 2019 - 2024. All rights reserved.