Mysql索引案例分析

这篇文章写个案例,测试一下MySQL索引机制

  1. 测试表结构
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='记录表';

  1. 给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);
  1. 给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);
  1. 给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);

表结构图

  1. t_qrcode_op
    Mysql索引案例分析_第1张图片
  2. u_record
    Mysql索引案例分析_第2张图片
  3. u_record_new(将pr_code列和op_mobile列用qr_id列代替,事实上这种表更好,因为不会需要检查一致性问题)
    Mysql索引案例分析_第3张图片

测试

# 先扫描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";

Mysql索引案例分析_第4张图片
Mysql索引案例分析_第5张图片
Mysql索引案例分析_第6张图片

你可能感兴趣的:(MySQL,mysql,数据库)