这篇文章写个案例,测试一下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)
begin
declare i int default 0;
declare startNum bigint default 13700000001;
lable:
while i<insertcount do
insert 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)
begin
declare i int default 0;
declare startNum bigint default 13700000001;
declare startNum1 bigint default 15100000001;
declare opm bigint ;
declare prc bigint ;
lable:
while i<insertcount do
set 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)
begin
declare 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 do
set 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";