您的位置:首页 > 数据库 > MySQL

mysql优化二:通过设置索引提高查询效率

2019-05-06 17:39 381 查看
MySQL数据库查询流程

mysql客户端通过协议与mysql服务器建立连接,发送查询语句,先检查查询缓存,如果命中,直接返回结果,否则进行语句解析,有一系列预处理,比如检查语句是否写正确了,然后是查询优化(比如是否使用索引扫描,如果是一个不可能的条件,则提前终止),生成查询计划,然后查询引擎启动,开始执行查询,从底层存储引擎调用API获取数据,最后返回给客户端。怎么存数据、怎么取数据,都与存储引擎有关。

索引的作用

索引通俗来讲就相当于书的目录,当我们根据条件查询的时候,没有索引,便需要全表扫描,数据量少还可以,一旦数据量超过百万甚至千万,一条查询sql执行往往需要几十秒甚至更多,5秒以上就已经让人难以忍受了。
提升查询速度的方向一是提升硬件(内存、cpu、硬盘),二是在软件上优化(加索引、优化sql;)。
能在软件上解决的,就不在硬件上解决,毕竟硬件提升代码昂贵,性价比太低。代价小且行之有效的解决方法就是合理的加索引。
索引使用得当,能使查询速度提升上万倍,效果惊人。

MySQL索引类型

mysql的索引有5种:主键索引、普通索引、唯一索引、全文索引、聚合索引(多列索引)。
唯一索引和全文索引用的很少,我们主要关注主键索引、普通索引和聚合索引。
1)主键索引:主键索引是加在主键上的索引,设置主键(primary key)的时候,mysql会自动创建主键索引;
2)普通索引:创建在非主键列上的索引;
3)聚合索引:创建在多列上的索引。

MySQL索引的语法

查看某张表的索引:show index from 表名;
创建普通索引:alter table 表名 add index 索引名 (加索引的列)
创建聚合索引:alter table 表名 add index 索引名 (加索引的列1,加索引的列2)
删除某张表的索引:drop index 索引名 on 表名;

创建一张测试表
drop table if exists test_user;
create table test_user(
id bigint varchar(20) primary key not null auto_increment,
username varchar(11) default null,
gender  varchar(2) default null,
password  varchar(100) default null
)engine = myisam default charset=utf8;

存储引擎使用MyISAM是因为此引擎没有事务,插入速度极快,方便我们快速插入千万条测试数据,等我们插完数据,再把存储类型修改为InnoDB

示例 使用存储过程插入1千万条数据
delimiter $$
create procedure insert_user1(in max_num int(10))
begin
declare i int default 0;
/*把autocommit设置成0*/
set autocommit= 0;
repeat
set i=i+1;
insert into test_user(username,gender,password)
values(i,'bm',PASSWORD(i));
until i=max_num end repeat;
commit;
end $$
插入数据

使用的MyISAM引擎,插入1千万条数据,耗时215.574秒,若是InnoDB引擎,插入100万条数据就要花费数小时了。
然后将存储引擎修改回InnDB。使用如下命令:

alter table test_user engine=InnoDB;

此命令执行时间大约耗时几分钟。

SQL测试
select id,username,gender,password from test_user where id = 99999;

耗时:0.003s。
因为我们建表的时候,将id设成了主键,所以执行此sql的时候,走了主键索引,查询速度才会如此之快。

select id,username,gender,password from test_user where username= 9000000;

耗时: 4.344s。
我们给username列加上普通索引。

ALTER TABLE `test_user` ADD INDEX index_name(username) ;

此过程耗时2分钟,建索引的过程会全表扫描,逐条建索引,当然慢了。
再来执行:

select id,username,gender,password from test_user where username=‘9000000’;

耗时:0.004s。
再用username和password来联合查询:

select id,username,gender,password  from test_user where username='9000000' or `password`='*3A70E147E88D99888804E4D472410EFD9CD890AE'

此时虽然我们队username加了索引,但是password列未加索引,索引执行password筛选的时候,还是会全表扫描,因此此时查询速度立马降了下来。
耗时:5.097s。
当我们的sql有多个列的筛选条件的时候,就需要对查询的多个列都加索引:
加上多列索引:

CREAT INDEX index_user_password ON test_user(username,password);

再来执行:
耗时:0.004s。

对于多列索引,只有在查询条件中使用了这些字段中第一个字段时,索引才会被使用。

select id,username,gender,password from test_user where username like ‘%900’;

使用like关键字进行查询的查询语言中,如果匹配字符串第一个字符为%索引不会起作用,查询用时0.055秒。

select id,username,gender,password from test_user where username like ‘900%’;

“%”不在第一个位置时索引才会起作用,用时0.02秒。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: