MySQL 右加入性能慢
MySQL right join slow performance
我有两个 table:
餐馆和调查邀请。
一家餐厅有多个调查邀请。
我想select所有有调查邀请且状态为'approved'、'completed'、'hidden_review'的餐厅。
餐厅 table 有 ~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`
解释是一样的
在 fiddle 中还有两个 table 上显示索引的结果。
我认为大约 240 万行需要 1.2 秒。
可能索引错了,我不太擅长这种东西。
编辑.1。
https://jsfiddle.net/bjuepb9j/6/
已显示创建 table 并显示 survey_invitations
的列
使用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
。此版本消除了这一点。
我建议将连接替换为 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`);
我有两个 table:
餐馆和调查邀请。
一家餐厅有多个调查邀请。
我想select所有有调查邀请且状态为'approved'、'completed'、'hidden_review'的餐厅。
餐厅 table 有 ~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`
解释是一样的
在 fiddle 中还有两个 table 上显示索引的结果。
我认为大约 240 万行需要 1.2 秒。 可能索引错了,我不太擅长这种东西。
编辑.1。 https://jsfiddle.net/bjuepb9j/6/
已显示创建 table 并显示 survey_invitations
的列使用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
。此版本消除了这一点。
我建议将连接替换为 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`);