场景还原:前一个月给朋友写了个简单的登录功能,简单的查询数据库登录逻辑,使用mysbatis-plus进行的dao层代码生成(吐槽一下这个工具,真是方便一时爽,后面维护难,比较喜欢自己能够组装和优化sql,大数据量插入时候mybatis-plus性能极差都是生成的单条插入sql然后flush),没想到啊,哥们的应用流量这么,数据量这么多。。很多问题都是这样,在小数据量,低频访问时候都是正常的,一旦有了流量很多问题就都出现了。用户点击登录按钮后,服务端长时间未响应。听到朋友描述后,我背后一凉,猜到可能是mysql出问题了,用的都是我自己搭建的,单台的mysql
查了一下资源使用情况
看完心凉了。。。mysql没加任何索引,都是全表查询,当时紧急处理,把所有用户登录数据导入redis(百万级的数据量,且密码是服务端生成,用户无法修改),暂时抗住了压力(之后回查了一下当时的流量 Max QPS 870左右)
通过这个应该可以算上事故的问题,下定决心要学习一下mysql的索引创建以及使用场景应用
学习过程:首先先创建一张测试表
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_name` varchar(32) NOT NULL DEFAULT '',
`nick_name` varchar(32) NOT NULL,
`pass_word` varchar(32) NOT NULL DEFAULT '',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
写一个生成1000万条数据的存储过程:
DELIMITER //
create procedure test_proc()
begin
declare num int DEFAULT 1;
while num <= 10000000 do
insert into user(user_name,nick_name,pass_word) values(num,'保密',PASSWORD(num));
set num=num+1;
end while;
end
//
DELIMITER ;
执行存储过程:(要等几分钟,如果觉得慢可以写一些拼接sql批插入)
call test_proc();
测试一下查询时间
select user_name,pass_word from user where user_name = '100000' or pass_word = '*8AB26805E964C278E555D5DA0C9F0D8';
MyISAM 查询需要1.53s
换一下InnoDB试一下 2.85s (MyISAM一般作为查询库,InnoDB有事务一般用在写比较的库)
这篇博客先使用一下最常用的普通索引进行一下优化:
alter table user add index index_user_name(user_name);
创建了一个简单索引之后的查询结果如下:
下面介绍一下可能会踩到的索引失效的坑:
1、如果是varchar类型没有加`` 符号还是会进行全表扫描
2、sql语句上尽可能不要用like,在索引字段上使用like还是会进行全表扫描
3、使用is null 或 is not null
4、使用函数作为where查询的条件
5、使用不等于操作符(<> ,!=,not in,in)
只是简单的加一下索引在user_name上就能优化这么明显,那是不是索引就能随便添加了呢?
1、如果是频繁更新的字段建了索引,更新字段的同时需要额外去更新索引
2、索引会占用比较大的磁盘空间去存储
3、唯一性太差的字段也不适合做索引
索引这么快速的提升了查询速度是怎么做到的呢?
周天的一个小小学习过程分享出来,比较初级,如有错误还请大神们指教