建表
CREATE TABLE `order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`creator` varchar(24) NOT NULL,
`price` varchar(64) NOT NULL,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`status` tinyint(1) not null,
PRIMARY KEY (`id`)
);
CREATE TABLE `order_item` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`parent` bigint(20) NOT NULL,
`status` int not null,
`type` varchar(12) NOT NULL DEFAULT '0',
`quantity` int not null default 1,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
待优化语句①
SELECT *
FROM `order` o
INNER JOIN order_item i ON i.parent = o.id
ORDER BY o.status ASC,
i.update_time DESC
LIMIT 0, 20;
o表大约2000数据,i表大约50W行数据
思路
o表的status只有1和0这2种值,分别令status的值=1和=0,分别取前20,再把结果集UNION ALL起来在进行一次排序。
如果不采用这种方式,将会走全表扫描之后再进行2次排序,扫描行数非常多,相当耗时
官方答案
SELECT o.*,i.*
FROM (
(SELECT o.id,
i.id item_id
FROM `order` o
INNER JOIN order_item i
ON i.parent =o.id
WHERE o.status = 0
ORDER BY i.update_time DESC
LIMIT 0, 20)
UNION ALL
(SELECT o.id,
i.id item_id
FROM `order` o
INNER JOIN order_item i
ON i.parent =o.id
WHERE o.status = 1
ORDER BY i.update_time DESC
LIMIT 0, 20)
) tmp
INNER JOIN `order` o ON tmp.id = o.id
INNER JOIN order_item i ON tmp.item_id =i.id
ORDER BY o.status ASC,
i.update_time DESC
LIMIT 0, 20;
需添加的索引
alter table order_item add index idx_1(update_time,parent);
alter table `order` add index idx_0(status);
待优化语句②
update `order` set
create_time = now()
where id in (
select parent from order_item where type = 2
);
该语句第一眼望过去涉及到2个知识点,第一个反应是in改inner join,第二个是临时表内的去重。
按照官方说法,这个语句除了上面的2个知识点外,还有对数据类型的核对,type是一个varchar类型,而临时表的查询直接改变了类型;其次在对临时表的去重过程中,很多人使用了distinct,按照官方说法,临时表的distinct会造成半连接失效,所以这里不能用distinct,而是需要用group by。
需要添加的索引
alter table `order` add index idx_1(type,parent);
语句改写
update `order` o inner join
(select type,parent from`order_item`where type='2' group by type,parent) i
on o.id = i.parent
set create_time =now();
关于半连接
MySQL半连接
大赛官方解析链接
腾讯云数据库优化初赛