什么是索引?
索引是帮助MySQL提高获取数据的数据结构,换一句话讲就是:排好序的快速查找的数据结构。
1、索引的分类
MySQL主要的几种索引类型:1.普通索引、2.唯一索引、3.主键索引、4.组合索引、5.全文索引。
1、普通索引
是最基本的索引,它没有任何限制。
2、唯一索引
与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
3、主键索引
是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。
主键索引和唯一索引的区别:
主键必唯一,但是唯一索引不一定是主键。
一张表上只能有一个主键,但是可以有一个或多个唯一索引。
4、组合索引
一个索引包含多个列,实际开发中推荐使用复合索引。
复合索引主要特点:
如果我们在创建了(name,age,xb)的复合索引,那么其实相当于创建了(name,age,xb)、(name,age)、(name)三个索引,这被称为最佳左前缀特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
MySQL InnoDB建立复合索引,a、b、c;那么查询条件where a = xxx and c = xxx 能用到索引吗?
答案:可以,但是c是不走索引的
注意事项:
1、对于复合索引,在查询使用时,写sql时候,最好将条件顺序按照索引的顺序,这样效率最高。
select * from table where col1 = A and col2 = B and col3 = C
2、如果使用 where col2=B and col1=A 或者 where col2=B 将不会使用索引
5、全文索引
全文搜索的索引。
FULLTEXT用于搜索很长一篇文章的时候,效果最好。用在比较短的文本,如果就一两行字的,普通的INDEX也可以。
综合小案例理解:
假如你在为某商场做一个会员卡系统。
这个系统有一个会员表
有下列字段:
会员编号 INT
会员姓名 VARCHAR(10)
会员身份证号码 VARCHAR(18)
会员电话 VARCHAR(10)
会员住址 VARCHAR(50)
会员备注信息 TEXT
那么这个 会员编号,作为主键,使用PRIMARY
会员姓名 如果要建索引的话,那么就是普通的INDEX
会员身份证号码,如果要建索引的话,那么可以选择UNIQUE(唯一的,不允许重复)
会员备注信息,如果需要建索引的话,可以选择FULLTEXT,全文搜索。
不过FULLTEXT用户搜很长一篇文章的时候,效果最好。
用在比较短的文本,如果就一两行字的,普通的INDEX也可以。
2、索引的优点和缺点
优点:
(1)、提高数据检索的效率,降低数据库IO成本
(2)、通过索引对数据进行排序,降低数据的排序成本,降低CPU的消耗。
缺点:
(1)、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
(2)、索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
3、是否需要创建索引
1、什么时候需要创建索引
(1)、主键自动创建唯一索引
(2)、较频繁的作为查询条件的字段。
(3)、查询中排序的字段,查询中统计或者分组的字段。
2、什么时候不需要创建索引
(1)、表记录太少的字段
(2)、经常增删改的字段
(3)、唯一性太差的字段,不适合单独创建索引。即使频繁的作为查询条件,比如性别,民族,政治面貌(可能总共也就那么几个或者几十个值)
4、索引的注意事项(优化)
1、尽量少使用模糊查询,如果要使用,那么通配符%可以出现在结尾,不能出现在开头。
如:name like ‘张%’,索引有效
而:name like ‘%张’,索引无效,全表查询
2、or会引起全表扫描
3、不要使用NOT、!=、NOT IN、NOT LIKE等
4、尽量少使用select ,而是根据需求来选择需要显示的字段*
5、索引不会包含有null值的列
只要列中包含有null值都将不会包含在索引中,复合索引有只要有一列含有null值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为null。
6、不要在列上计算,这将导致索引失效而进行全表扫描
7、使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个char(255)的列,如果在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和IO操作。
8、UNION并不绝对比OR的执行效率高
我们前面已经谈到了在where子句中使用or会引起全表扫描,一般的,我所见过的资料都是推荐这里用UNION来代替or。事实证明,这种说法对于大部分都是适用的。
有一点不适用:如果or两边的查询列是一样的话,那么用UNION则反倒和用OR的执行速度差很多,虽然这里UNION扫描的是索引,而or扫描的是全表。
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' or fariqi=''2004-2-5''
用时:6423毫秒。扫描计数 2,逻辑读 14726 次,物理读 1 次,预读 7176 次。
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-2-5''
用时:11640毫秒。扫描计数 8,逻辑读 14806 次,物理读 108 次,预读 1144 次。
5、索引方式(结构)
mysql中的存储引擎:myisam,innodb,memory
memory用的是hash索引
myisam,innodb 用的是b+tree索引
大部分说的存储引擎都是innodb。
Hash索引:
所谓Hash索引,放我们要给某张表某列增加索引时,将这张表的这一类进行哈希算法计算,得到哈希值,排序在哈希数组上。索引Hash索引可以一次定位,其效率很高,而B+Tree索引需要经过多次的磁盘IO。
因为Hash索引比较的是经过Hash计算的值,所以在 = in < = >(安全等于)的时候,它的效率是非常高的,但我们开发一般会选择innodb的B+Tree,Hash会存在如下一些缺点。
(1)、Hash索引仅仅能满足= in <=>查询,不能使用范围查询。
由于Hash索引比较的是进行Hash运算之后的Hash值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样
(2)、Hash索引无法被用来避免数据的排序操作
由于Hash索引中存放的是经过Hash计算之后的Hash值,而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算。
(3)、Hash索引不能利用部分索引键查询
对于组合索引,Hash索引在计算Hash值的时候是组合索引键组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用。
(4)、Hash索引在任何时候都不能避免表扫描
前面已经知道,Hash索引是经索引键通过Hash运算之后,将Hash运算结构的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同的Hash值,所以即使取满足Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。
(5)、Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B+Tree索引高
B+Tree有2中查找方式:从根节点开始查找;也可以通过双向链表从最小叶子节点开始查找。
MYISAM和INNODB的数据结构都是B+Tree,从上图中可以看到:
Innodb最后的叶子节点存放的是完整数据,这种数据和索引存放在一起的叫做聚簇索引。
Myisam最后的叶子节点存放的是地址,通过地址再查找数据,这种数据和索引分开的叫做非聚簇索引。