mysql

MySQL --- 索引机制

2021-04-15  本文已影响0人  _code_x

说说你对 MySQL 索引的理解?

索引有哪些优缺点?

优势:

劣势:

MySQL有哪几种索引类型?(或者说索引是怎么实现的?)

Mysql目前主要有以下几种结构的索引类型:B+Tree 索引、哈希索引、全文索引(full-index)与空间数据索引(R-Tree)

为什么索引默认用 B+树,而不用B树、二叉树、hash和红黑树呢?

为什么不用B-tree

为什么不用Hash方式呢?

二叉树: 树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。

红黑树/AVL树: 树的高度随着数据量增加而增加,IO代价高。如果存在频繁的插入、删除操作,那么AVL树自平衡,红黑树的左旋和右旋等比较影响性能。

拓展:磁盘预读原理

1.文件很大,不可能全部存储在内存中,故要存储到磁盘上
2.索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数(为什么使用B-/+Tree,还跟磁盘存取原理有关。)
3.局部性原理与磁盘预读,预读的长度一般为页(page)的整倍数(在许多操作系统中,页得大小通常为4k)
4.数据库系统巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入,(由于节点中有两个数组,所以地址连续)。而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性

聚集索引与非聚集索引的区别?

首先mysql聚簇和非聚簇索引都是B+树结构。

聚集/聚簇索引(Innodb默认):即索引结构和数据一起存放的索引,主键索引属于聚集索引。数据的物理存放顺序与索引的顺序是一致的,一个表只能有一个聚集索引**。在 Mysql 中,InnoDB 引擎的表的 .ibd文件就包含了该表的索引和数据,对于 InnoDB 引擎表来说,该表的索引(B+树)的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据。

  1. 依赖于有序的数据 :因为 B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。

  2. 维护代价大 : 如果对索引列的数据被修改时,那么对应的索引也将会被修改, 而且聚集索引的叶子节点还存放着数据,修改代价肯定是较大的, 所以对于主键索引来说,主键一般都是不可被修改的。

非聚集索引非聚集索引即索引结构和数据分开存放的索引。二级索引属于非聚集索引。表中记录的物理顺序与键值的索引顺序不同。这也是非聚集索引与聚集索引的根本区别。注意:非聚集索引的叶子节点并不一定存放数据的指针(行地址), 因为二级索引的叶子节点就存放的是主键,根据主键再回表查数据。MYISAM 引擎的表的.MYI 文件包含了表的索引, 该表的索引(B+树)的每个叶子非叶子节点存储索引, 叶子节点存储索引和索引对应数据的指针,指向.MYD 文件的数据。ps:类似先找到书的目录,再找到对应的页码。

  1. 跟聚集索引一样,非聚集索引也依赖于有序的数据

  2. 可能会二次查询(回表) :这应该是非聚集索引最大的缺点了。 当查到索引对应的指针或主键后,可能还需要根据指针或主键再到数据文件或表中查询。

非聚簇索引一定会回表查询(覆盖索引)吗?

答:不一定,如果涉及到查询语句所要求的字段全部命中了索引,那么就不必再进行回表查询。

试想一种情况,用户准备使用 SQL 查询用户名,而用户名字段正好建立了索引。

 SELECT name FROM table WHERE name='guang19';

那么这个索引的 key 本身就是 name,查到对应的 name 直接返回就行了,无需回表查询。

覆盖索引:需要查询的字段值正好是索引的字段(或者说索引字段已经覆盖了我们的查询需求),那么直接根据该索引,就可以查到数据了, 而无需回表查询。

我们知道在 InnoDB 存储引擎中,如果不是主键索引,叶子节点存储的是主键+列值。最终还是要“回表”,也就是要通过主键再查找一次。这样就会比较慢覆,覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!

当然,索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。

explain:SQL语句的执行计划

我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过在SQL语句前面加explain命令来查看。

id:选择标识符
select_type:表示查询的类型。
table:输出结果集的表
partitions:匹配的分区
type:表示表的连接类型
possible_keys:表示查询时,可能使用的索引
key:表示实际使用的索引
key_len:索引字段的长度
ref:列与索引的比较
rows:扫描出的行数(估算的行数)
filtered:按表条件过滤的行百分比
Extra:执行情况的描述和说明

InnoDB引擎中的索引策略,了解过吗?

InnoDB主键索引与辅助索引的结构InnoDB引擎索引结构的叶子节点的数据域,存放的就是实际的数据记录(对于主索引,此处会存放表中所有的数据记录;对于辅助索引此处会引用主键,检索的时候通过主键到主键索引中找到对应数据行),或者说,InnoDB的数据文件本身就是主键索引文件,这样的索引被称为"“聚簇索引”,一个表只能有一个聚簇索引。

InnoDB 索引结构需要注意的点:

  1. 数据文件本身就是索引文件
  2. 表数据文件本身就是按 B+Tree 组织的一个索引结构文件
  3. 聚集索引中叶节点包含了完整的数据记录
  4. InnoDB 表必须要有主键,并且推荐使用整型自增主键

正如我们上面介绍 InnoDB 存储结构,索引与数据是共同存储的,不管是主键索引还是辅助索引,在查找时都是通过先查找到索引节点才能拿到相对应的数据。

创建索引的方式有哪些?

创建索引有三种方式:

CREATE TABLE user_index2 (
    id INT auto_increment PRIMARY KEY,
    first_name VARCHAR (16),
    last_name VARCHAR (16),
    id_card VARCHAR (18),
    information text,
    KEY name (first_name, last_name),
    FULLTEXT KEY (information),
    UNIQUE KEY (id_card)
);
ALTER TABLE table_name ADD INDEX index_name (column_list);

ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。

其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。

索引名index_name可自己命名,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引

CREATE INDEX index_name ON table_name (column_list);

创建索引时原则有哪些?需要注意什么?

索引创建的原则

创建索引的注意点

ps:联合索引与单列索引的区别:

为什么使用自增主键作为索引?那为什么推荐使用整型自增主键而不是选择UUID?

结合B+Tree的特点,自增主键是连续的,在插入过程中尽量减少页分裂,即使要进行页分裂,也只会分裂很少一部分。并且能减少数据的移动,每次插入都是插入到最后。总之就是减少页分裂和移动的频率

使用索引查询一定能提高查询的性能吗?

通常通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价。

索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时,索引本身也会被修改。 这意味着每条记录的INSERT,DELETE,UPDATE将为此多付出4,5 次的磁盘I/O。 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能,索引范围查询(INDEX RANGE SCAN)适用于两种情况:

MySql如何使用索引?

ps:模糊查询时,%如果在前面,那么不会使用索引。在实际使用时,如果涉及到多列,我们一般都不会将这些列一 一创建为单列索引,而是将这些列创建为组合索引。

ps:一般必须符合最左前缀原则:假设组合索引为:a,b,c的话;那么当SQL中对应有:a或a,b或a,b,c的时候,可称为完全满足最左原则;当SQL中查询条件对应只有a,c的时候,可称为部分满足最左原则;当SQL中没有a的时候,可称为不满足最左原则。注:MySQL5.7开始,会自动优化,符合最左前缀原则。

查询语句是否用到索引的分析?

在查询语句前面加上explain(explain执行计划)

我们只需要注意一个最重要的type 的信息很明显的体现是否用到索引。一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。Key为实际使用的索引。

UUID和int自增主键的区别

UUID:由于UUID是随机生成的 插入时位置具有一定的不确定性,无序插入,会存在许多内存碎片,内存空间的占用量也会比自增主键大,区间查找也没自增主键性能优

自增主键:在进行数据库插入时,位置相对固定(B+树中的右下角)增加数据插入效率,减少插入的磁盘IO消耗,每页的空间在填满的情况下再去申请下一个空间,底层物理连续性更好,能更好的支持区间查找

总之,访问量大时,用UUID;访问量小时,用自增ID;

以上仅供学习使用

参考鸣谢:

http://cyc2018.gitee.io/cs-notes/#/notes/MySQL?id=myisam
https://www.nowcoder.com/discuss/639644type=post&order=time&pos=&page=1&channel=-1&source_id=search_post_nctrack
https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/database/MySQL.md

上一篇下一篇

猜你喜欢

热点阅读