目录mysql
1.在关系型数据库中,索引是一种单独的、物理层面的对数据表中一列或多列的值进行排序的一种存储结构,也称之为keysql
2.能够理解:搜索引导,索引是一个特殊的数据结构,其存储的是数据的关键信息与详细信息的位置关系,例如:图书的目录,能够根据目录中的页码快速找到所需的内容数据库
3.有三种索引:unique key、primary key、index key数据结构
加速查询,当数据量很是大的时候,查询某一个数据集是很是慢,索引是提高查询效率最有效的手段测试
1.注意:在数据库中插入数据会引起索引的重建优化
2.不是说有了索引就能加速,得看你的查询语句有没有正确使用索引操作系统
3.索引也须要占用额外的数据空间设计
4.添加索引后将致使增减删除修改变慢(写入)code
1.查询操做较多,写入较少而且数据量很大时视频
2.查询与写入操做的占比为 10:1 ,或者查询更多时
1.数据库的索引,实现思路与字典是一致的,须要一个独立的存储结构,专门存储索引数据
2.本质上索引是经过不断缩小查询范围来提升查询效率
1.平均查找一个数据须要花费至少9.15ms,这段时间CPU就会切换到其余的程序
2.操做系统预读取:当一次io时,不光把当前磁盘地址的数据读取,而是把相邻的数据也都读取到内存缓冲区中,这个理论对于索引的数据结构设计很是有帮助
3.咱们要加速查询,必须减小io操做的次数
1.b+树(第一层为根节点只能有一个,中间层为分支节点,最下面的是叶子节点,当叶子节点过多时,分支节点势必也会相应的增长,上面的根节点也就须要多个,因为根节点有且只有一个的特性,所以只能增长层数,那么查询时遇到的io操做也就相应的增长了,影响效率):
2.在b+树种,叶子节点才是存储真实数据的,叶子数量越多,树的层级越高,进而致使io操做增长(一层一个io操做)
3.要避免这个问题,在叶子节点中尽量的存储更多的数据,应该将数据量小的字段做为索引
1.当b+树的数据项是复合的数据结构,好比(name,age,sex)的时候(多字段联合索引),b+树会按照从左到右的顺序来创建搜索树,好比当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来肯定下一步的所搜方向,若是name相同再依次比较age和sex,最后获得检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪一个节点,由于创建搜索树的时候name就是第一个比较因子,必需要先根据name来搜索才能知道下一步去哪里查询。好比当(张三,F)这样的数据来检索时,b+树能够用name来指定搜索方向,但下一个字段age的缺失,因此只能把名字等于张三的数据都找到,而后再匹配性别是F的数据了, 这个是很是重要的性质,即索引的最左匹配特性
2.索引在查找时,是按照从左往右依次比较,若是查询语句没有出现最左边的索引,将没法加速查询
1.汇集索引种包含了全部字段的值,若是已指定了主键,主键就是汇集索引,若是没有则找一个非空且惟一的字段做为汇集索引,若是连这个也找不到,则自动生成一个字段做为汇集索引
2.汇集索引中存储了全部的数据
1.除了汇集索引之外的都叫作辅助索引,包括foreign key
与unique
2.辅助索引中只包含当前的索引字段和主键的值
1.指的是在当前索引结构中就能找到全部须要的数据,若是使用的是汇集索引来查询那么必定覆盖查询,速度是最快的
2.若是覆盖索引指定的数据仅在辅助索引中能找到,则不须要再查找汇集索引数据就能找到:
# 好比 # 假设stu表的name字段是一个辅助索引 select name from stu where name = 'jack':
1.指的是在当前索引结构中(辅助索引)找不到所需的数据,须要经过主键id去汇集索引中查询,速度慢于汇集索引
2.步骤:从辅助索引中获取主键的值,再拿着主键值到汇集索引中找到sex值
# 好比 # name字段是一个辅助索引,而sex字段不是索引 select sex from stu where name = 'jack';
汇集索引 > 覆盖索引 > 非覆盖索引
# 建表 create table usr(id int,name char(10),gender char(3),email char(30)); #准备数据 delimiter // create procedure addData(in num int) begin declare i int default 0; while i < num do insert into usr values(i,"jack","m",concat("xxxx",i,"@qq.com")); set i = i + 1; end while; end// delimiter ; #执行查询语句 观察查询时间 select count(*) from usr where id = 1; #1 row in set (3.85 sec) #时间在秒级别 比较慢 1. #添加主键 alter table usr add primary key(id); #再次查询 select count(*) from usr where id = 1; #1 row in set (0.00 sec) #基本在毫秒级就能完成 提高很是大 2. #当条件为范围查询时 select count(*) from usr where id > 1; #速度依然很慢 对于这种查询没有办法能够优化由于须要的数据就是那么多 #缩小查询范围 速度立马就快了 select count(*) from usr where id > 1 and id < 10; #当查询语句中匹配字段没有索引时 效率测试 select count(*) from usr where name = "jack"; #1 row in set (2.85 sec) # 速度慢 3. # 为name字段添加索引 create index name_index on usr(name); # 再次查询 select count(*) from usr where name = "jack"; #1 row in set (3.89 sec) # 速度反而下降了 为何? #因为name字段的区分度很是低 彻底没法区分 ,由于值都相同 这样一来B+树会没有任何的子节点,像一根竹竿每一都匹配至关于,有几条记录就有几回io ,全部要注意 区分度低的字段不该该创建索引,不能加速查询反而下降写入效率, #同理 性别字段也不该该创建索引,email字段更加适合创建索引 # 修改查询语句为 select count(*) from usr where name = "aaaaaaaaa"; #1 row in set (0.00 sec) 速度很是快由于在 树根位置就已经判断出树中没有这个数据 所有跳过了 # 模糊匹配时 select count(*) from usr where name like "xxx"; #快 select count(*) from usr where name like "xxx%"; #快 select count(*) from usr where name like "%xxx"; #慢 #因为索引是比较大小 会从左边开始匹配 很明显全部字符都能匹配% 因此全都匹配了一遍 4.索引字段不能参加运算 select count(*) from usr where id * 12 = 120; #速度很是慢缘由在于 mysql须要取出全部列的id 进行运算以后才能判断是否成立 #解决方案 select count(*) from usr where id = 120/12; #速度提高了 由于在读取数据时 条件就必定固定了 至关于 select count(*) from usr where id = 10; #速度天然快了 5.有多个匹配条件时 索引的执行顺序 and 和 or #先看and #先删除全部的索引 alter table usr drop primary key; drop index name_index on usr; #测试 select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com"; #1 row in set (1.34 sec) 时间在秒级 #为name字段添加索引 create index name_index on usr(name); #测试 select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com"; #1 row in set (17.82 sec) 反而时间更长了 #为gender字段添加索引 create index gender_index on usr(gender); #测试 select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com"; #1 row in set (16.83 sec) gender字段任然不具有区分度 #为id加上索引 alter table usr add primary key(id); #测试 select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx1@qq.com"; #1 row in set (0.00 sec) id字段区分度高 速度提高 #虽然三个字段都有索引 mysql并非从左往右傻傻的去查 而是找出一个区分度高的字段优先匹配 #改成范围匹配 select count(*) from usr where name = "jack" and gender = "m" and id > 1 and email = "xxxx1@qq.com"; #速度变慢了 #删除id索引 为email创建索引 alter table usr drop primary key; create index email_index on usr(email); #测试 select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com"; #1 row in set (0.00 sec) 速度很是快 #对于or条件 都是从左往右匹配 select count(*) from usr where name = "jackxxxx" or email = "xxxx0@qq.com"; #注意 必须or两边都有索引才会使用索引 and 语句中只要有一个存在索引就能提升速度 6.多字段联合索引 为何须要联合索引 案例: select count(*) from usr where name = "jack" and gender = "m" and id > 3 and email = "xxxx2@qq.com"; 假设全部字段都是区分度很是高的字段,那么除了id为谁添加索引都可以提高速度,可是若是sql语句中没有出现索引字段,那就没法加速查询,最简单的办法是为每一个字段都加上索引,可是索引也是一种数据,会占用内存空间,而且下降写入效率 此处就可使用联合索引, 联合索引最重要的是顺序 按照最左匹配原则 应该将区分度高的放在左边 区分度低的放到右边 #删除其余索引 drop index name_index on usr; drop index email_index on usr; #联合索引 create index mul_index on usr(email,name,gender,id); create index mul_index on usr(id,email,gender,name); # 推荐 # 查询测试 select count(*) from usr where name = "xx" and id = 1 and email = "xx"; 只要语句中出现了最左侧的索引(email) 不管在前在后都能提高效率 drop index mul_index on usr;
1.使用占用空间最小的字段做为索引
2.不要在一行中存储太多的数据,例如小说、视频,若是字段太多能够分表
3.尽可能使用覆盖查询
4.若是字段区分度低(字段重复度高),创建索引是没有意义的,反过来讲应该将区分度高的字段(好比自增的id)做为索引
5.模糊匹配中,百分号尽可能不要写在前面
**6.不要在等号的左边作运算,例如:select count(*) from usr where id*3 = 6 -- 也会遍历全部记录 ;**
7.and语句中会自动找一个具有索引的字段优先执行,因此咱们应该在and语句中至少包含一个具有索引的字段
8.or语句要避免使用,若是要用,则要保证全部字段都有索引才能加速
9.联合索引中,顺序应该将区分度最高的放到左边,最低的放到右边,查询语句中必须保证最左边的索引出如今语句中
1.若是要查询的数据量很是大时,索引将没法加速
2.不是添加了索引就能提速,须要考虑索引添加的是否合理,SQL语句是否使用到了索引
create index 索引的名字 on 表名称(字段名);
drop index 索引名称 on 表名;
create index 索引名称 on 表名(字段名1,字段名2,......)