mysql 查询中 select 的 select 的优化
optimization for select of select in mysql query
我的 mysql 查询需要将近 7 秒来获取数据,其中我使用了 select 的 select。
SELECT s.id
, s.user_id
, COUNT(s.od_status) od_status
, (SELECT count(t2.od_status)
FROM subscription t2
WHERE od_status <> 3
AND t2.od_status <> 7
AND t2.od_status <> 8
AND t2.user_id = s.user_id
AND DATE(IF(t2.rescheduling_delivery_date IS NULL, t2.dated, t2.rescheduling_delivery_date)) BETWEEN DATE_FORMAT('2021-07-26', '%Y-%m-01') AND '2021-07-26'
) od_status_count
FROM subscription
LEFT
JOIN users u
ON u.id = s.user_id
WHERE DATE(IF(s.rescheduling_delivery_date IS NULL, s.dated, s.rescheduling_delivery_date)) BETWEEN DATE_FORMAT('2021-07-26' , '%Y-%m-01') AND '2021-07-26'
GROUP
BY s.user_id;
我需要优化上面的查询,我得到 7 秒的是在上面的查询 select of select
下方添加
(select count(t2.od_status) from subscription t2 where od_status<>3 and t2.od_status<>7 and t2.od_status<>8
and t2.user_id=subscription.user_id and
date(IF(t2.rescheduling_delivery_date IS NULL,t2.dated,t2.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26') as od_status_count
任何优化建议或其他使用方法。
注意:我已将 index
给 subscription
user_id
table
为了使优化器能够使用索引,您需要:
- 改写您的查询。使用
OR
或 UNION
/UNION ALL
. 移除 IF() 函数
- 删除 date() 函数并用时间戳比较代替它。
如果不这样做,您仍然可以通过为子查询添加索引来获得更好的性能。这是最简单的选择,但不会真正得到很大的改进。您可以添加以下索引:
create index ix1 on subscription (user_id, od_status);
为了进一步提高性能,您可以改用覆盖索引:
create index ix1 on subscription (
user_id,
od_status,
rescheduling_delivery_date,
dated,
rescheduling_delivery_date
);
按照 @RahulBiswas 的建议,我将子查询更改为 LEFT JOIN 并且查询在 0.16
秒
内执行
select
`subscription`.`id`,
`subscription`.`user_id`,
COUNT(subscription.od_status) as od_status ,
x.od_status_count
from `subscription` left join `users` on `users`.`id` = `subscription`.`user_id`
left join(
select t2.user_id,count(t2.od_status)as od_status_count from subscription t2 where od_status<>3 and t2.od_status<>7 and t2.od_status<>8
and
date(IF(t2.rescheduling_delivery_date IS NULL,t2.dated,t2.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26'
group by t2.user_id)x
on x.user_id=subscription.user_id
where date(IF(subscription.rescheduling_delivery_date IS NULL,subscription.dated,subscription.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26'
group by `subscription`.`user_id`
我将子查询更改为如下连接,
left join(
select t2.user_id,count(t2.od_status)as od_status_count from subscription t2 where od_status<>3 and t2.od_status<>7 and t2.od_status<>8
and
date(IF(t2.rescheduling_delivery_date IS NULL,t2.dated,t2.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26'
group by t2.user_id)x
on x.user_id=subscription.user_id
我的 mysql 查询需要将近 7 秒来获取数据,其中我使用了 select 的 select。
SELECT s.id
, s.user_id
, COUNT(s.od_status) od_status
, (SELECT count(t2.od_status)
FROM subscription t2
WHERE od_status <> 3
AND t2.od_status <> 7
AND t2.od_status <> 8
AND t2.user_id = s.user_id
AND DATE(IF(t2.rescheduling_delivery_date IS NULL, t2.dated, t2.rescheduling_delivery_date)) BETWEEN DATE_FORMAT('2021-07-26', '%Y-%m-01') AND '2021-07-26'
) od_status_count
FROM subscription
LEFT
JOIN users u
ON u.id = s.user_id
WHERE DATE(IF(s.rescheduling_delivery_date IS NULL, s.dated, s.rescheduling_delivery_date)) BETWEEN DATE_FORMAT('2021-07-26' , '%Y-%m-01') AND '2021-07-26'
GROUP
BY s.user_id;
我需要优化上面的查询,我得到 7 秒的是在上面的查询 select of select
下方添加
(select count(t2.od_status) from subscription t2 where od_status<>3 and t2.od_status<>7 and t2.od_status<>8
and t2.user_id=subscription.user_id and
date(IF(t2.rescheduling_delivery_date IS NULL,t2.dated,t2.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26') as od_status_count
任何优化建议或其他使用方法。
注意:我已将 index
给 subscription
user_id
table
为了使优化器能够使用索引,您需要:
- 改写您的查询。使用
OR
或UNION
/UNION ALL
. 移除 IF() 函数
- 删除 date() 函数并用时间戳比较代替它。
如果不这样做,您仍然可以通过为子查询添加索引来获得更好的性能。这是最简单的选择,但不会真正得到很大的改进。您可以添加以下索引:
create index ix1 on subscription (user_id, od_status);
为了进一步提高性能,您可以改用覆盖索引:
create index ix1 on subscription (
user_id,
od_status,
rescheduling_delivery_date,
dated,
rescheduling_delivery_date
);
按照 @RahulBiswas 的建议,我将子查询更改为 LEFT JOIN 并且查询在 0.16
秒
select
`subscription`.`id`,
`subscription`.`user_id`,
COUNT(subscription.od_status) as od_status ,
x.od_status_count
from `subscription` left join `users` on `users`.`id` = `subscription`.`user_id`
left join(
select t2.user_id,count(t2.od_status)as od_status_count from subscription t2 where od_status<>3 and t2.od_status<>7 and t2.od_status<>8
and
date(IF(t2.rescheduling_delivery_date IS NULL,t2.dated,t2.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26'
group by t2.user_id)x
on x.user_id=subscription.user_id
where date(IF(subscription.rescheduling_delivery_date IS NULL,subscription.dated,subscription.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26'
group by `subscription`.`user_id`
我将子查询更改为如下连接,
left join(
select t2.user_id,count(t2.od_status)as od_status_count from subscription t2 where od_status<>3 and t2.od_status<>7 and t2.od_status<>8
and
date(IF(t2.rescheduling_delivery_date IS NULL,t2.dated,t2.rescheduling_delivery_date))
between DATE_FORMAT('2021-07-26' ,'%Y-%m-01') AND '2021-07-26'
group by t2.user_id)x
on x.user_id=subscription.user_id