这篇文章写个案例,测试一下MySQL索引机制
- 测试表结构
CREATE TABLE `t_qrcode_op` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`op_mobile` varchar(16) NOT NULL,`pr_code` char(10) NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `om_pc` (`op_mobile`,`pr_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='url短码记录表';CREATE TABLE `u_record` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`cu_mobile` varchar(16) NOT NULL,`op_mobile` varchar(16) NOT NULL,`pr_code` varchar(20) NOT NULL,`in_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '时间',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `cm_pc` (`cu_mobile`,`pr_code`)
) ENGINE=InnoDB AUTO_INCREMENT=574 DEFAULT CHARSET=utf8 COMMENT='记录表';CREATE TABLE `u_record_new` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`cu_mobile` varchar(16) NOT NULL,`qr_id` int(11) NOT NULL,`in_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=574 DEFAULT CHARSET=utf8 COMMENT='记录表';
- 给t_qrcode_op表新增2000条数据
-- 删除存储过程
drop procedure if exists proc_insertQrOp;-- 创建存储过程
delimiter $$
create procedure proc_insertQrOp(in insertcount int)
begindeclare i int default 0;declare startNum bigint default 13700000001;lable:while i<insertcount doinsert into t_qrcode_op(op_mobile,pr_code)values(concat(startNum+i,""),concat("P",10001+i));set i=i+1;end while lable;
end $$
delimiter;-- 清空表的原有数据
delete from t_qrcode_op;-- 调用存储过程
call proc_insertQrOp(2000);
- 给u_record表新增2000条数据
-- 删除存储过程
drop procedure if exists proc_insertRecord;-- 创建存储过程
delimiter $$
create procedure proc_insertRecord(in insertcount int)
begindeclare i int default 0;declare startNum bigint default 13700000001;declare startNum1 bigint default 15100000001;declare opm bigint ;declare prc bigint ;lable:while i<insertcount doset opm = startNum+floor(i/2);set prc = 10001+floor(i/2);insert into u_record(cu_mobile,op_mobile,pr_code)values(concat(startNum1+i,""),concat(opm,""),concat("P",prc));set i=i+1;end while lable;
end $$
delimiter;-- 清空表的原有数据
delete from u_record;-- 调用存储过程
call proc_insertRecord(2000);
- 给u_record_new插入2000条数据
-- 删除存储过程
drop procedure if exists proc_insertRecordNew;-- 创建存储过程
delimiter $$
create procedure proc_insertRecordNew(in insertcount int)
begindeclare i int default 0;declare startNum bigint default 13700000001;declare startNum1 bigint default 15100000001;declare opm bigint ;declare prc bigint ;declare qrid int;lable:while i<insertcount doset opm = startNum+floor(i/2); set prc = 10001+floor(i/2);select id into qrid from t_qrcode_op where op_mobile = concat(opm,"") and pr_code = concat("P",prc);insert into u_record_new(cu_mobile,qr_id)values(concat(startNum1+i,""),qrid);set i=i+1;end while lable;
end $$
delimiter;-- 清空表的原有数据
delete from u_record_new;-- 调用存储过程
call proc_insertRecordNew(2000);
表结构图
- t_qrcode_op
- u_record
- u_record_new(将pr_code列和op_mobile列用qr_id列代替,事实上这种表更好,因为不会需要检查一致性问题)
测试
# 先扫描rn,再查找o.id时用了主键索引
explain
select *
from u_record_new rn left join t_qrcode_op o on rn.qr_id = o.id;# 先扫描o,再查找rn.qr_id时进行全表扫描
explain
select *
from t_qrcode_op o left join u_record_new rn on o.id = rn.qr_id;# 走了索引
explain
select *
from u_record where cu_mobile = "15100000804";# 没走索引,最左前缀
explain
select *
from u_record where pr_code = "P10405";# 走了索引
explain
select *
from u_record where cu_mobile = "15100000804" and pr_code = "P10402";# 走了索引
explain
select *
from u_record where pr_code = "P10402" and cu_mobile = "15100000804";