MySQL(1)-索引总结

1-1.索引

索引即用于快速定位数据的特征值,可以使用数据表中的某一/几列来作为索引。

1-1.1 分类

1-1.1.1 按结构

1)B+TREE
(1)定义

B+树是2-3树的扩展,其将3节点进一步放大为n节点以容纳更多的元素,其中中间节点只存储子节点的头部索引,叶子节点存放数据,且索引值由小到大从左至右排列,各个叶子节点构成一个单链表,这样更适用于顺序的批量查询。此外,由于要查询数据必须到叶子节点才可以得到,因而相较于B树更加稳定

(2)匹配规则
  • 全值匹配

  • 匹配最左前缀(索引最左一列)

  • 匹配最左前缀的前缀(索引最左一列的左前缀)

  • 一个范围查询

    即从索引最左开始,只能按顺序出现一个范围查询条件且位于最后

(3)失效情况
  • 不是从最左匹配

  • 跳过索引中的某几列匹配

  • 某一列范围查询,则后面的列不能使用索引

InnoDB和MyISAM均使用B+TREE索引

2)HASH索引
(1)定义

为数据计算HASH值并存储与HASH表中,并采用拉链法解决HASH冲突

(2)匹配规则

使用HASH值定位bin的位置,再遍历链表来查找对应的数据

(3)失效情况
  • 不能使用覆盖索引 因为索引节点的值只用于存储HASH值,不用于存储节点的值

  • 有序的数据其对应的HASH值不一定有序,因而不能使用HASH索引提供ORDER BY,同样不支持范围查询

  • 不能匹配列的前缀或某一列,因为HASH一般利用全部列进行计算得到

  • HASH冲突很多的数据不适用

自适应HASH

InnoDB中会对经常访问到的索引基于B-TREE索引构建HASH索引以进一步加快访问

自定义HASH

如果使用了B-TREE索引,且某一列的数据很长且适用于计算HASH值,那么可以使用HASH值来进行避免以避免其他类型(字符串匹配)的低效匹配

3)空间树索引R-TREE

索引无须前缀查询,且可以利用任意维度的列进行匹配,需要结合GIS相关函数

4)全文索引

不是单纯的匹配索引的值,而是匹配索引的关键词

1-1.1.2 按内容

  • 单值索引

    单个列构成的索引

  • 组合索引

    几个列有序构成的索引

  • 聚簇索引

    叶子节点同时存储了索引值、事务ID、回滚指针和对应的其他全部列数据,可以减少磁盘IO的次数

  • 非聚簇索引

    叶子节点只存储的索引的值及对应行数据的指针,需要根据指针再进行一次磁盘IO来得到行数据

  • 覆盖索引

    索引即包含了所有要查询的值

  • 前缀索引

    使用索引值中的前缀

1-1.1.3 按存储引擎

1)InnoDB
(1)主键

聚簇索引

如果以主键列为索引查询,那么只需要遍历索引树找到对应的条目(叶子节点)即可得到要查询的数据

(2)非主键

非聚簇索引

子节点中存储了索引+主键的值,那么需要根据主键再遍历一遍主键的索引树来查找对应的数据

2)MyISAM

全部采用非聚簇索引

子节点存储了索引+对应行数据的指针,那么在找到对应的叶子节点之后还需要根据指针再进行一次磁盘IO才可以找到要查询的数据

图片来自高性能MySQL(第3版)

index

1-1.2 优势

  • 二分查找加快访问速度

  • B-TREE可以提供额外的ORDER BY GROUP BY 辅助,也即是顺序IO

  • InnoDB利用索引可以避免全表扫描以减少行锁的加锁个数

1-1.3 失效场景

  • 对要索引的列使用函数

  • 使用!=进行判断

  • 使用 IS NULL判断

  • 使用LIKE判断时将不确定部分也即%放在最左侧,形如LIKE "%aa"

  • ORDER BY时列的顺序不同于索引中列的顺序

1-1.4 常用命令

创建

CREATE INDEX indexName ON table_name (column_name);

添加

ALTER table tableName ADD INDEX indexName(columnName);

添加前缀索引(需要根据前缀的选择性来指定前缀的长度)

ALTER TABLE table_name ADD KEY(column_name(prefix_length));

删除

DROP INDEX [indexName] ON mytable;

显示索引

SHOW INDEX FROM table_name; \G

修复/优化表

ALTER TABLE <table> ENGINE=<engine>;

1-2. 索引优化

1-2.1 查询流程

一条sql语句从客户端发出到服务端需要经历以下步骤才可以被执行

  • 连接器

    用于进行用户名、密码验证

  • 分析器

    对sql语句进行语法、语义上的验证

  • 优化器

    对sql语句按照mysql认为最优的策略生成执行方案

  • 执行器

    验证权限,按照执行方案调用存储引擎的接口执行sql查询

1-2.2 慢查询原因

1-2.2.1 冗余查询

1)多余行

进行范围查询时,是查询到所有的数据后再进行过滤,这样有可能导致查询了许多不必要的数据

可以使用LIMIT进行限制以返回更少的有用信息

2)多余列

尽量不使用select *,只查询必要的列

1-2.2.2 低效过滤

一般MySQL能够使用如下三种方式应用WHERE条件,从好到坏依次如下

  • 索引中使用WHERE条件来过滤不匹配的记录。这是在存储引擎层完成的

  • 使用索引覆盖扫描(在Extra列中出现了Using index)来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL的server层完成的,但无须再回表查询记录,由于使用到了覆盖索引

  • 由存储引擎层回表查询并返回数据给server层,然后在server层过滤不满足条件的记录(在Extra列中出现Using Where)

MySQL的server层和存储引擎层是如何交互的 - 掘金 (juejin.cn)

1-2.2.3 优化器逆优化

mysql优化后的执行计划可能不是最优

1-2.3 慢查询优化

1-2.3.1 重构查询语句

如果一条sql可以被拆解为多条sql,且被拆分出的sql查询的结果可以被多次重用,那么可以用拆分后的多条sql来替代原来的一条查询任务繁重的sql

1-2.3.2 切分查询范围

如果要查询10000条记录,可以分为100组,每组查100条

1-2.4 分析查询

使用EXPLAIN关键字+sql语句即可对sql语句进行分析

EXPLAIN中得到的rows是最终返回结果扫描的行数,而不是实际扫描的行数,例如关联查询结果返回的一条记录通常是由多条记录组成。

posted @ 2021-02-02 15:52  Linus1  阅读(72)  评论(0编辑  收藏  举报