索引

为什么使用索引

  1. 大大减少了服务器需要扫描的数据量
  2. 帮助服务器避免排序和临时表
  3. 将随机io变成顺序io

索引用处

  1. 快速查找匹配WHERE子句的行
  2. 从consideration中消除行,如果可以在多个索引之间进行选择,mysql通常会使用找到最少行的索引
  3. 如果表具有多列索引,则优化器可以使用索引的任何最左前缀来查找行
  4. 当有表连接的时候,从其他表检索行数据
  5. 查找特定索引列的min或max值
  6. 如果排序或分组时在可用索引的最左前缀上完成的,则对表进行排序和分组
  7. 在某些情况下,可以优化查询以检索值而无需查询数据行

索引使用条件

  • 小表全表扫描效率优于索引
  • 索引适合中大型表
  • 特大型表,建立和维护索引的代价将会随之增长

一些索引数据结构

  • hash
    • 可以直接根据key访问
    • 但是无法进行范围查询
  • avl
    • 平衡二叉树,左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值(平衡因子 ) 不超过1
    • 支持范围查询
    • 插入操作可能需要旋转,效率低
  • b+树

B+ Tree原理

B-tree减少了定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统

B+树中叶子节点中包含了key和value,非叶子节点中只是包含了key,不包含value 所有叶子节点位于同一层

批注 2020-03-10 192507

操作

  • 查找

首先在根节点进行二分查找,找到一个key的指针,接下来递归地不断向其非叶子节点查找,到了叶子节点,再进行二分查找,找出key所对应的data

  • 修改操作会破坏平衡性,所以修改之后会进行分裂、合并、旋转

vs红黑树

  • 红黑树的出度为2,B树的出度要大很多,所以B树的查找次数更少
  • B+ Tree能更好地利用磁盘的预读特性

MYSQL索引

技术名词

  • 回表
  • 最左匹配
  • 索引下推

分类

  • 主键索引
  • 唯一索引
  • 普通索引
  • 全文索引
  • 组合索引

B+ Tree索引

  • 是大多数 MySQL 存储引擎的默认索引类型
  • 除了用于查找,还可以用于排序和分组
  • 适用于全键值、键值范围和键前缀查找

存储引擎的实现

MyISAM: B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”

InnoDB: 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。 因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂

哈希索引

  • 无法用于排序与分组
  • 只支持精确查找,无法用于部分查找和范围查找

只有MyISAM引擎显式支持哈希索引。对于索引比较长的字符序列,哈希索引很好用

InnoDB当某些索引值被使用的非常频繁时,会在B树索引的基础上创建一个哈希索引

全文索引

  • MyISAM 存储引擎支持(innodb 5.6后支持)
  • 用于查找文本中的关键词
  • 查找条件使用 MATCH AGAINST
  • 使用倒排索引

空间数据索引

间数据索引(R-Tree),可以用于地理数据存储

索引匹配方式

  • 全值匹配 全值匹配指的是和索引中的所有列进行匹配
explain select * from staffs where name = 'July' and age = '23' and pos = 'dev'
  • 匹配最左前缀 只匹配前面的几列
explain select * from staffs where name = 'July' and age = '23';
explain select * from staffs where name = 'July';
  • 匹配列前缀 可以匹配某一列的值的开头部分
explain select * from staffs where name like 'J%'; -- 可以用索引
explain select * from staffs where name like '%y'; -- 用不到索引
  • 匹配范围值 可以查找某一个范围的数据
explain select * from staffs where name > 'Mary';
  • 精确匹配某一列并范围匹配另外一列 可以查询第一列的全部和第二列的部分
explain select * from staffs where name = 'July' and age > 25;
  • 只访问索引的查询 查询的时候只需要访问索引,不需要访问数据行,本质上就是覆盖索引
explain select name,age,pos from staffs where name = 'July' and age = 25 and pos = 'dev';

组合索引

当包含多个列作为索引,需要注意的是正确的顺序依赖于该索引的查询,同时需要考虑如何更好的满足排序和分组的需要

聚簇索引与非聚簇索引

一种数据存储方式。

聚簇索引:不是单独的索引类型,而是一种数据存储方式,指的是数据行跟相邻的键值紧凑的存储在一起

屏幕截图 2021-03-09 172129

非聚簇索引:数据文件跟索引文件分开存放

覆盖索引

如果一个索引包含所有需要查询的字段的值,称之为覆盖索引,当需要的数据被索引覆盖时,就不必回表查询。

只使用索引可以减少数据读取量,同时由于索引是顺序存储的,相比直接读取数据,拥有较好的IO性能。

MySQL中只能使用B树索引做覆盖索引

EXPLAIN SELECT store_id,film_id FROM inventory; -- Extra:Using index 代表可以做覆盖索引

MyISAM和InnoDB对B+Tree的使用

MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录

myisam

2020325193319

innodb

202032519307

索引优化

如果表很大,索引反而会造成性能下降

如果有索引,增删改都会变慢

少量查询仍然很快

但是并发大的时候会受到硬盘带宽影响

独立的列

进行查询时,索引列不能是表达式的一部分,也不能是函数的参数

SELECT a FROM B WHERE a+3 = 6; -- a不能作为索引

主键索引

尽量使用主键查询,而不是其他索引,因此主键查询不会触发回表查询

多列索引

多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好

MySQL会进行一项称为索引合并的策略,一定程度上可以使用多个单列索引来定位指定的行

组合索引

当一个索引不止一个列时,只有当最左索引(索引的第一个列)出现时,才会走索引查询

索引列的顺序

在不考虑排序和分组时,让选择性最强的索引列放在前面

一个列比另外一个列更越能确定一条数据,则前者选择性更强。但还有一种情况就是数据分布不均匀,也有可能造成索引的效果非常差

前缀索引

BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符

前缀索引无法进行ORDER BY 或者GEOUP BY,也无法进行覆盖扫描。

有时候又需要后缀索引,为了达成这个目的,一种hack的方式是把字符串反转后进行存储

覆盖索引

索引包含所有需要查询的字段的值

  • 只读取索引能大大减少数据访问量
  • 一些存储引擎只缓存索引

索引扫描

使用EXPLAIN时 ,type为index,代表使用了索引扫描来进行排序

使用索引扫描来排序

只有当索引的列顺序和order by子句的顺序完全一致,并且所有列的排序方式都一样时,mysql才能够使用索引来对结果进行排序

冗余索引

大多数情况下应尽量扩展已有的索引而非创建新索引,索引越多,更新的时候越慢。

但有时候为了兼容多个查询情况,为创建冗余索引来提升性能

细节

union all,in,or都能够使用索引,但是推荐使用in

范围列可以用到索引 范围条件是:<、<=、>、>=、between 范围列可以用到索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列

强制类型转换会全表扫描

更新十分频繁,数据区分度不高的字段上不宜建立索引 更新会变更B+树,更新频繁的字段建议索引会大大降低数据库性能 区分不大的属性,建立索引是没有意义的,不能有效的过滤数据

创建索引的列,不允许为null,可能会得到不符合预期的结果

当需要进行表连接的时候,最好不要超过三张表,因为需要join的字段,数据类型必须一致

  • 三种join实现方式

能使用limit的时候尽量使用limit

单表索引建议控制在5个以内

单索引字段数不允许超过5个(组合索引)

一些错误概念:

  • 索引越多越好
  • 过早优化

索引监控

show status like 'Handler_read%';
  • Handler_read_first:读取索引第一个条目的次数
  • Handler_read_key:通过index获取数据的次数
  • Handler_read_last:读取索引最后一个条目的次数
  • Handler_read_next:通过索引读取下一条数据的次数
  • Handler_read_prev:通过索引读取上一条数据的次数
  • Handler_read_rnd:从固定位置读取数据的次数
  • Handler_read_rnd_next:从数据节点读取下一条数据的次数

维护索引和表

CHECK TABLE 命令可以找出大多数表和索引的错误,使用REPAIR TABLE来修复损坏的表

使用ANALYZE TABLE 重新生成表的统计信息

使用OPTIMIZE TABLE来整理碎片,对于不支持的存储引擎,执行

ALTER TABLE table_name ENGINE=old_engine

results matching " "

No results matching " "

results matching " "

No results matching " "