1、索引不是万能
- 数据行数少的状况下,索引效率没什么做用
- 当数据重复度大,好比高于 10% 的时候,也不须要对这个字段使用索引
2、索引类型
1.功能逻辑分类
普通索引 |
|
惟一索引 |
|
主键索引 |
|
全文索引 |
|
2.物理实现分类
汇集索引 |
|
非汇集索引 |
|
3.字段个数分类
单一索引 | 索引列为一列 |
联合索引 | 多个列组合在一块儿建立 |
4.索引片中包含的匹配列的数量不一样
窄索引 | 包含索引列数为 1 或 2 |
宽索引 | 包含的索引列数大于 2) |
3、联合索引的最左原则
联合索引(x,y,z),索引查询,必须出现由左到右的查询条件才有效(不是编写SQL的where顺序,是要查y的时候,必有x做为查询条件才能够),从左到右的使用索引中的字段sql
4、为何用B+树来作索引
名称 | 树形 | 局限性 |
二叉树 | |
|
平衡二叉树 | ![]() |
|
BTree | ![]() |
|
B+Tree | ![]() |
|
- 磁盘的 I/O 操做次数对索引的使用效率相当重要
- 虽然传统的二叉树数据结构查找数据的效率高,但很容易增长磁盘 I/O 操做的次数,影响索引使用的效率
- 在构造索引的时候,更倾向于采用“矮胖”的数据结构
- B 树和 B+ 树均可以做为索引的数据结构,在 MySQL 中采用的是 B+ 树,B+ 树在查询性能上更稳定,在磁盘页大小相同的状况下,树的构造更加矮胖,所须要进行的磁盘 I/O 次数更少
- 子节点进行了链表连接更适合进行关键字的范围查询
5、Hash索引
- Hash 自己是一个函数,又被称为散列函数,它能够帮助咱们大幅提高检索数据的效率
- 只须要一次交互就能够完成查找,效率很是高
Hash | B+Tree | |
范围查询 |
|
|
联合索引的最左侧原则 |
|
|
ORDER BY 排序 |
|
|
模糊查询 |
|
|
等值查询 |
|
|
MySQL 中的 Memory 存储引擎支持 Hash 存储,其余不支持,如InnoDB数据库
6、Mysql 自适应 Hash 索引
MySQL 的 InnoDB 存储引擎还有个“自适应 Hash 索引”的功能,就是当某个索引值使用很是频繁的时候,它会在 B+ 树索引的基础上再建立一个 Hash 索引,这样让 B+ 树也具有了 Hash 索引的优势,这个功能不须要人工干预数组
- 自适应哈希索引只保存热数据(常常被使用到的数据),并不是全表数据。所以数据量并不会很大,可让自适应Hash放到缓冲池中,也就是InnoDB buffer pool,进一步提高查找效率
- InnoDB中的自适应Hash至关因而“索引的索引”,采用Hash索引存储的是B+树索引中的页面的地址
- 自适应Hash采用Hash函数映射到一个哈希表中,因此对于字典类型的数据查找很是方便哈希表是数组+链表的形式
InnoDB自己不支持Hash,可是提供自适应Hash索引,不须要用户来操做,而是存储引擎自动完成的。自适应Hash也是InnoDB三大关键特性之一数据结构
7、建立索引规律
索引太多了,在更新数据的时候,若是涉及到索引更新,就会形成负担函数
须要建立索引的状况性能
- 字段的数值有惟一性的限制
- 频繁做为 WHERE 查询条件的字段,尤为在数据表大的状况下
- 须要常常 GROUP BY 和 ORDER BY 的列
- 多个单列索引在多条件查询时只会生效一个索引(MySQL 会选择其中一个限制最严格的做为索引),多条件联合查询的时候最好建立联合索引
- UPDATE、DELETE 的 WHERE 条件列,通常也须要建立索引
- DISTINCT 字段须要建立索引
不须要建立索引的状况优化
- WHERE 条件(包括 GROUP BY、ORDER BY)里用不到的字段不须要建立索引
- 若是表记录太少,好比少于 1000 个,那么是不须要建立索引的
- 字段中若是有大量重复数据,也不用建立索引
- 频繁更新的字段不必定要建立索引,更新数据的时候,也须要更新索引,若是索引太多,在更新索引的时候也会形成负担,从而影响效率
索引失效的状况搜索引擎
- 若是索引进行了表达式计算,则会失效
- 若是对索引使用函数,会形成失效
- 在 WHERE 子句中,若是在 OR 前的条件列进行了索引,而在 OR 后的条件列没有进行索引,那么索引会失效,由于 OR 的含义就是两个只要知足一个便可,所以只有一个条件列进行了索引是没有意义的,只要有条件列没有进行索引,就会进行全表扫描,所以索引的条件列也会失效
- 当咱们使用 LIKE 进行模糊查询的时候,前面不能是 %,如%xxx
- 索引列尽可能设置为 NOT NULL 约束
- 联合索引的时候要注意最左原则
8、索引片和过滤因子
- SQL 查询语句在执行中须要扫描的一个索引片断
- 索引片越宽,须要顺序扫描的索引页就越多
- 索引片越窄,就会减小索引访问的开销
经过宽索引避免回表
学生表(学号,姓名,课程ID,课程名),主键(学号)spa
select 学号,姓名,课程ID,课程名 from 学生表 where 课程ID in (1,2,3);
窄索引(课程ID)设计
- 经过窄索引,找到主键(定位数据行)
- 根据主键(数据行),回表查找相应数据
- 取出select须要的数据
宽索引(课程ID,姓名,课程名)
- 直接经过宽索引找到select须要的数据
优势:经过宽索引将 SELECT 中须要用到的列(主键列能够除外)都设置在宽索引中,这样就避免了回表扫描的状况
缺点:宽索引须要顺序扫描的索引页不少
过滤因子
- 描述了谓词的选择性。在 WHERE 条件语句中,每一个条件都称为一个谓词,谓词的选择性也等于知足这个条件列的记录数除以总记录数的比例
学生表(学号,姓名,课程ID,性别,年龄)
- 假设重复率:性别50%,姓名14%,课程ID28%,年龄43%
- 性别,年龄不是好过滤因子
- 联合过滤因子有更高的过滤能力
- 须要注意一个条件,那就是条件列的关联性应该尽可能相互独立,不然若是列与列之间具备相关性,联合过滤因子的能力就会降低不少
- 好比城市名称和电话区号就有强相关性,这两个列组合到一块儿不会增强过滤效果
- 过滤因子决定了索引片的大小
- 过滤因子的条件过滤能力越强,知足条件的记录数就越少,SQL 查询须要扫描的索引片也就越小
- 若是没有选择好索引片中的过滤因子,就会形成索引片中的记录数过多的状况
三星索引
- 在 WHERE 条件语句中,找到全部等值谓词中的条件列,将它们做为索引片中的开始列
- 将 GROUP BY 和 ORDER BY 中的列加入到索引中
- 将 SELECT 字段中剩余的列加入到索引片中
- 经过索引查找符合条件的记录,就须要将 WHERE 子句中的等值谓词列加入到索引片中,这样索引的过滤能力越强,最终扫描的数据行就越少
- 要对数据记录分组或者排序,都须要从新扫描数据记录。为了不进行 file sort 排序,能够把 GROUP BY 和 ORDER BY 中涉及到的列加入到索引中
- 建立了索引就会按照索引的顺序来存储数据,这样再对这些数据按照某个字段进行分组或者排序的时候,就会提高效率
很难存在理想的索引设计
- 采用三星索引会让索引片变宽,这样每一个页可以存储的索引数据就会变少,从而增长了页加载的数量
- 从另外一个角度来看,若是数据量很大,好比有 1000 万行数据,过多索引所须要的磁盘空间可能会成为一个问题,对缓冲池所需空间的压力也会增长,增长了索引维护的成本
- 若是为全部的查询语句都设计理想的三星索引,就会让数据表中的索引个数过多,这样索引维护的成本也会增长
- 当添加一条记录的时候,就须要在每个索引上都添加相应的行(存储对应的主键值)
- 假设添加一行记录的时间成本是 10ms(磁盘随机读取一个页的时间)
- 若是咱们建立了 10 个索引,添加一条记录的时间就可能变成 0.1s,若是是添加 10 条记录呢?就会花费近 1s 的时间
- 从索引维护的成原本看消耗仍是很高的
- 固然对于数据库来讲,数据的更新不必定立刻回写到磁盘上,但即便不及时将脏页进行回写,也会形成缓冲池中的空间占用过多,脏页过多的状况