索引在MySQL中也称作'键',是存储引擎用于快速找到记录的一种数据结构.索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发更重要.
索引优化是对查询性能优化的手段,索引能够轻易将查询性能提高好几个量级.如果没有索引,则需要逐页去查询,可想而知效率就会低下
索引是应用程序设计和开发的一个重要方面。若索引太多,应用程序的性能可能会受到影响。而索引太少,对查询性能又会产生影响,要找到一个平衡点,这对应用程序的性能至关重要。一些开发人员总是在事后才想起添加索引
通过不断地缩小想要获取数据的范围来少选出最终想要的结果,同时把随机的事件变成顺序的事件
当一次IO时,不光把当前磁盘地址的数据读出,而且还把相邻的数据也读到内存缓冲区内.
当计算机再次访问一个地址的数据时,与其相邻的数据也会很快被访问到,每次IO读取的数据成为一页page,一页的数据量(block块)一般为4K或是8K,与操作系统设置有关,这个理论对于索引的数据结构设计非常有帮助
每次查询数据时把磁盘IO次数控制在一个很小的数量级
树状图是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合.
特点:
1.每个节点有0个或多个子节点;
2.没有父节点的节点成为根节点
3.每一个非根节点有且只有一个父节点;
4.除了根节点外,每个子节点可以分为多个不相交的子树(子节点)
如图下图:?
根节点:A
父节点:A是B,C的父节点
叶子节点:D,E是叶子节点
树的深度/高度: 深度为 3
由二叉查找树进化成--->平衡二叉树(balance Tree)最终进化成--->B+树
b+树的性质:
1.索引字段要尽量的小
通过上面的分析,我们知道IO次数取决于b+数的高度h,假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N一定的情况下,m越大,h越小;而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小,数据项的数量越多,树的高度越低。这就是为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半。这也是为什么b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度下降,导致树增高。当数据项等于1时将会退化成线性表。2.索引的最左匹配特性
b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+数是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。 3.数据只存储在叶子节点上 如: 数据 + 索引
4.在叶子节点上添加双向地址链接(链指针),更方便叶子节点之间进行数据的读取
1.InnoDB存储引擎是索引组织表,即表中数据按照主键存放,由每张表的主键构成一颗B+树,同时叶子节点存放整张表的行记录数据,聚集索引的叶子节点也成为数据页. (数据 + 索引)
2.未定义主键,mysql默认自定义一个非空+唯一键(字段),作为聚集索引,但是这个字段不能被使用.
3.数据页只能是一颗B+树进行排序,因此每张表只拥有一个聚集索引
4.在多数情况下,查询优化器更倾向于采用聚集索引.因为每个聚集索引能够在B+树索引的叶子节点上直接获取找到数据,由于定义了数据的逻辑顺序,聚集索引能够特别快地访问针对范围值查询
好处:
1.它对主键的排序查找和范围查找速度非常快,叶子节点的数据及时用户索要查询的数据.如用户需要查询一张表,查询最后10位用户信息,由于B+树索引是双向链表,所以用户可以快速找到最后一个数据页,并直接取出数据
### 没有添加 主键索引 前 mysql> select * from s1 order by id desc limit 10; +---------+------+--------+-------------------+ | id | name | gender | email | +---------+------+--------+-------------------+ | 2999999 | eva | female | eva2999999@oldboy | | 2999998 | eva | female | eva2999998@oldboy | | 2999997 | eva | female | eva2999997@oldboy | | 2999996 | eva | female | eva2999996@oldboy | | 2999995 | eva | female | eva2999995@oldboy | | 2999994 | eva | female | eva2999994@oldboy | | 2999993 | eva | female | eva2999993@oldboy | | 2999992 | eva | female | eva2999992@oldboy | | 2999991 | eva | female | eva2999991@oldboy | | 2999990 | eva | female | eva2999990@oldboy | +---------+------+--------+-------------------+ 10 rows in set (3.93 sec) # 3秒多 # 添加主键 mysql> alter table s1 add primary key(id); Query OK, 0 rows affected (44.24 sec) Records: 0 Duplicates: 0 Warnings: 0 ### 再次查询 ,添加主键后,不难发现运行速度快了 mysql> select * from s1 order by id desc limit 10; +---------+------+--------+-------------------+ | id | name | gender | email | +---------+------+--------+-------------------+ | 2999999 | eva | female | eva2999999@oldboy | | 2999998 | eva | female | eva2999998@oldboy | | 2999997 | eva | female | eva2999997@oldboy | | 2999996 | eva | female | eva2999996@oldboy | | 2999995 | eva | female | eva2999995@oldboy | | 2999994 | eva | female | eva2999994@oldboy | | 2999993 | eva | female | eva2999993@oldboy | | 2999992 | eva | female | eva2999992@oldboy | | 2999991 | eva | female | eva2999991@oldboy | | 2999990 | eva | female | eva2999990@oldboy | +---------+------+--------+-------------------+ 10 rows in set (0.00 sec) # 毫秒级响应2.范围查询(range query) 如果要查询主键某一范围内的数据,通过叶子节点的上层中间节点就可以获得到页的范围,可以直接读取数据
mysql> alter table s1 drop primary key; Query OK, 2699998 rows affected (24.23 sec) Records: 2699998 Duplicates: 0 Warnings: 0 mysql> desc s1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | | name | varchar(20) | YES | | NULL | | | gender | char(6) | YES | | NULL | | | email | varchar(50) | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ rows in set (0.12 sec) mysql> explain select * from s1 where id > 1 and id < 1000000; #没有聚集索引,预估需要检索的rows数如下 +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 2690100 | 11.11 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ row in set, 1 warning (0.00 sec) mysql> alter table s1 add primary key(id); Query OK, 0 rows affected (16.25 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> explain select * from s1 where id > 1 and id < 1000000; #有聚集索引,预估需要检索的rows数如下 +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | s1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 1343355 | 100.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ row in set, 1 warning (0.09 sec) 1.除了聚集索引其他索引都是辅助索引,与聚集索引的区别是:辅助索引的叶子节点不包含行记录的全部数据
2.叶子节点出了包含键值意外,每个叶子节点中的索引还包含了一个书签(bookmark),该书签用来告诉innoDB存储引擎去哪里可以找到与索引相对应的行数据 (一行数据的某个字段的数据 如: age + 索引)
3.回表查询,拿到具体的索引,如果需要查询表中这个索引的其他数据,需要重新依据索引查询这一行的其他数据
4.每张表可以有多个辅助索引,但只能有一个聚集索引.当通过辅助索引来寻找数据时,InnoDB存储引擎会遍历辅助索引并通过叶子级别的指针获得只想主键索引的主键,然后再通过主键索引来找到一个完整的行记录。
1.索引的功能就是加快查找
2.mysql中的primary key ,unique ,联合唯一也都是索引,除了加速查找以外,还有约束功能
1.在没有索引的前提下测试查询速度
#无索引:mysql根本就不知道到底是否存在id等于333333333的记录,只能把数据表从头到尾扫描一遍,此时有多少个磁盘块就需要进行多少IO操作,所以查询速度很慢 mysql> select * from s1 where id=333333333; Empty set (0.33 sec) 2.在表中已经存在大量数据的前提下,为某个字段段建立索引,建立速度会很慢
3.在索引建立完毕后,以该字段为查询条件时,查询速度提升明显
1.mysql先去索引表里根据b+树的搜索原理很快搜索到id等于333333333的记录不存在,IO大大降低,因而速度明显提升**
2. 我们可以去mysql的data目录下找到该表,可以看到占用的硬盘空间多了
详细说明索引未命中
联合索引指的是表上的多个列合并起来做一个索引
InnoDB存储引擎支持覆盖索引,即从辅助索引中就可以得到查询记录,则不需要查询聚集索引中的记录
# 覆盖索引 using index # select count(id) from 表; # select id from 表 where id <20; # 索引合并 # 创建的时候是分开创建的 # 用的时候临时和在一起了 # using union 表示索引合并 1.查看sql语句的执行计划
2.explain select * from s1 where id<10000;
3.是否命中了索引,命中的索引的类型
### 执行计划:让mysql预估执行操作(一般正确) all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const id,email 慢: select * from userinfo3 where name='alex' explain select * from userinfo3 where name='alex' # type: ALL(全表扫描) select * from userinfo3 limit 1; 快: select * from userinfo3 where email='alex' # type: const(走索引)
尽量用固定长度的数据类型替代可变的数据类型
把固定长度的字段放在前面
如果列表中的数据越多,查询效率越低
列多:垂直分表
航多:水评分表
1.尽力把条件写的细致些,where条件做筛选
2.多表尽量连表查询代替子查询
3.创建有效的索引,规避掉无效的索引
开启慢日志查询,确认具体的有问题的sql,或者效率慢的sql
读写分离操作
转载于:https://www.cnblogs.com/dengl/p/11335428.html