【问题标题】:MySQL right join slow performanceMySQL右连接性能慢
【发布时间】:2018-05-09 08:56:52
【问题描述】:

我有两张桌子:

餐厅和调查邀请。

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

我想选择所有收到调查邀请且状态为“已批准”、“已完成”、“隐藏评论”的餐厅。

餐馆表有约 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`

解释是一样的。

在小提琴中还有两个表上显示索引的结果。

我认为大约 240 万行需要 1.2 秒。 也许索引是错误的,我不太擅长这种东西。

编辑.1。 https://jsfiddle.net/bjuepb9j/6/

有 show create table 和 show columns ofsurvey_invitations

【问题讨论】:

  • 你能分享你的带有索引和(主键/唯一键)的表创建语句吗?
  • 你为什么使用RIGHT JOIN?使用右连接,右连接条件上的表永远不会为空(因为 null 不等于 null),这意味着 Restaurants 表是可选的,但是您可以在 where 子句中通过执行来否定它针对Restaraunts 表(country_id 和 area_id)进行相等性检查。我认为内部连接会更简单。尝试一下,看看它如何影响性能。 (内连接提供了更多优化选项)

标签: performance indexing mysql-5.7 right-join


【解决方案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 中。这个版本消除了这一点。

【讨论】:

  • 在 0.6 秒内工作。感谢存在,因为我不需要数据。
【解决方案2】:

我建议将连接替换为 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`);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 2012-07-01
    • 1970-01-01
    • 2016-09-11
    • 2017-08-13
    • 1970-01-01
    • 2015-07-29
    • 2020-09-12
    相关资源
    最近更新 更多