MySQL索引
索引
为什么要有索引:索引一般是为了快速查询数据,才会有的索引。
什么是索引:索引在mysql中叫做‘键’是存储引擎用于快速知道记录的一种数据结构。
原理:索引的目的在于提高快速查询效率,本质都是通过不断的缩小范围最后筛选出最终想要的结果,同时也是把随机事件变成了顺序事件,也就是说,我们在一组数据量大的情况下可以使用同一种的查询方式来锁定想要的结果。
索引的数据结构
- 树状图是一种数据结果欧,它是由n(n-1)个有限结点组成的一个具有层次关系的集合。之所以叫它树,是因为它看起来就是一个倒挂的树,因为他的根在上,树枝在下的。
特点:
- 每个节点有零个或者多个子结点,
- 没有父结点的结点叫根结点
- 每一个非根结点有且只有一个父结点
- 除了根结点外,每个子节点课分为多个不相关的子树。
B+树的特征:
- 1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。
- 2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
- 3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
B+树的优势:
- 1.单一节点存储更多的元素,使得查询的IO次数更少。
- 2.所有查询都要查找到叶子节点,查询性能稳定。
- 3.所有叶子节点形成有序链表,便于范围查询。
B+树索分为引聚集索引(clustered index)和辅助索引(secondary index)
- 相同点:内部都是B+树的形式,即高度都是平衡的,叶子结点存放的着所有的数据
- 不同点是:叶子结点存放的是不是一整行的信息
聚集索引就是按照每张表的主键构造⼀棵B+树,同时叶⼦结点存放的即为整张表的⾏记录数据,也将聚集索引的叶⼦结点称为数据⻚。聚集索引的这个特性决定了索引组织表中数据也是索引的⼀部分。同B+树数据结构⼀样,每个数据⻚都通过⼀个双向链表来进⾏链接。
聚集索引的好处:
- 它对主键的排序查找和范围查找速度非常快,叶⼦节点的数据就是⽤户所要查询的数据。如⽤户需要查找⼀张表,查询最后的10位⽤户信息,由于B+树索引是双向链表,所以⽤户可以快速找到最后⼀个数据⻚,并取出10条记录
范围查询(range query),即如果要查找主键某⼀范围内的数据,通过叶⼦节点的上层中间节点就可以得到⻚的范围,之后直接读取数据⻚即可辅助索引的叶⼦节点不包含⾏记录的全部数据
- 叶⼦节点除了包含键值以外,每个叶⼦节点中的索引⾏中还包含⼀个书签(bookmark)。该书签⽤来告诉InnoDB存储引擎去哪⾥可以找到与索引相对应的⾏数据。
- 由于InnoDB存储引擎是索引组织表,因此InnoDB存储引擎的辅助索引的书签就是相应⾏数据的聚集索引键。
聚集索引
- 1.纪录的索引顺序与⽆⼒顺序相同因此更适合between and和order by操作
- 2.叶⼦结点直接对应数据从中间级的索引⻚的索引⾏直接对应数据⻚
- 3.每张表只能创建⼀个聚集索引
非聚集索引
- 1.索引顺序和物理顺序⽆关
- 2.叶⼦结点不直接指向数据⻚
- 3.每张表可以有多个非聚集索引,需要更多磁盘和内容多个索引会影响insert和update的速度
功能:
- 1. 索引的功能就是加速查找
- 2. mysql中的primary key,unique,联合唯⼀也都是索引,这些索引除了加速查找以外,还有约束的功能
MySQL常用的索引
普通索引INDEX:加速查找
唯一索引:
- 主键索引PRIMARY KEY :加速查找+约束(不为空、不能重复)
- 唯一索引UNIQUE :加速查找+约束(不能重复)
联合索引:
- PRIMARY KEY(id,name):联合主键索引
- UNIQUE (id,name):联合唯一索引
- INDEX(id,name):联合普通索引
索引的两大类型:hash与btree
我们可以在创建上述索引的时候,为其指定索引类型,分两类
- hash类型的索引:查询单条快,范围查询慢
- btree类型的索引:b+树,层数越多,数据量指数级增⻓(我们就⽤它,因为innodb默认⽀持它)
不同的存储引擎⽀持的索引类型也不⼀样
- InnoDB ⽀持事务,⽀持⾏级别锁定,⽀持 B-tree、Full-text 等索引,不⽀持 Hash 索引;
- MyISAM 不⽀持事务,⽀持表级别锁定,⽀持 B-tree、Full-text 等索引,不⽀持 Hash 索引;
- Memory 不⽀持事务,⽀持表级别锁定,⽀持 B-tree、Hash 等索引,不⽀持 Full-text 索引;
- NDB ⽀持事务,⽀持⾏级别锁定,⽀持 Hash 索引,不⽀持 B-tree、Full-text 等索引;
- Archive 不⽀持事务,⽀持表级别锁定,不⽀持 B-tree、Hash、Full-text 等索引;
创建/删除索引的语法
方式一:
create table t1(
id int,
name char,
age int,
sex enum('male','female'),
unique key uni_id(id),
index ix_name(name) #index没有key
);
create table t1(
id int,
name char,
age int,
sex enum('male','female'),
unique key uni_id(id),
index(name) #index没有key
);
方式二:
create index ix_age on t1();
方式三:
- alter table 表名 add index ix_字段名(字段名);
- alter table 表名 add index(字段名);
无索引:mysql 根本就不知道到底是否存在id等于333333333的记录,只能把数据表从头到尾扫描⼀遍,此时有多少个磁盘块就需要进⾏多少IO操作,所以查询速度很慢在大量数据下,为某个字段建立索引,建立速度很慢,但是建立完后,查询速度提升
1 正确使用索引:
索引未命中:范围问题,或则说条件不明确,条件中出现这些符号或关键字:>、<、>=、<=、!=、between...and...*like,大于号,小于号
不等于!=:
- select 字段名 from 表名 where id!=数值;
- between...and:select 字段名 from 表名 where id between 数 and 数;
like:
- select 字段名 from 表名 where Emily like‘明确的值’;速度快
- select 字段名 from 表名 where Emily like‘xxx%’;速度快
- select 字段名 from 表名 where Emily like‘%xxxx’;速度慢
2 尽量选择区分度⾼的列作为索引,区分度的公式是count(distinct col)/count(*),表⽰字段不重复的比例,比例越⼤我们扫描的记录数越少,唯⼀键的区分度是1,⽽⼀些状态、性别字段可能在⼤数据⾯前区分度就是0,那可能有⼈会问,这个比例有什么经验值吗?使⽤场景不同,这个值也很难确定,⼀般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录
3 索引列不能在条件中参与计算,保持列“⼲净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使⽤到索引,原因很简单,b+树中存的都是数据表中的字段值,但进⾏检索时,需要把所有元素都应⽤函数才能比较,显然成本太⼤。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)
4 and/or
1、and与or的逻辑
- 1.条件1 and 条件2 :所条件成立才算成立,但凡一个条件不成立则最终结果不成立
- 2.条件1 or 条件2 :只要有一个条件成立则最终结果就成立
2、and的⼯作原理
- 条件:
a = 10 and b = 'xxx' and c > 3 and d =4
- 索引:
制作联合索引(d,a,b,c)
- ⼯作原理:
对于连续多个and:mysql会按照联合索引,从左到右的顺序找⼀个区分度⾼的索引字段(这样便可以快速锁定很⼩的范围),加速查询,即按照d—>a->b->c的顺序
3、or的⼯作原理
- 条件:
a = 10 or b = 'xxx' or c > 3 or d =4
- 索引:
制作联合索引(d,a,b,c)
- ⼯作原理:
对于连续多个or:mysql会按照条件的顺序,从左到右依次判断,即a->b->c->d
5 最左前缀匹配原则(详⻅第八⼩节),非常重要的原则,对于组合索引mysql会⼀直向右匹配直到遇到范围查询(>、<、between、like)就停⽌匹配(指的是范围⼤了,有索引速度也慢),比如a = 1 and b = 2 and c > 3and d = 4 如果建立(a,b,c,d)顺序的索引,d是⽤不到索引的,如果建立(a,b,d,c)的索引则都可以⽤到,a,b,d的顺序可以任意调整。