mysql学习与提高3:mysql索引

目录

索引

B Tree 原理

索引分类

B+Tree 索引

哈希索引

全文索引

空间数据索引(R-Tree)

索引的特点

索引的优点

索引的缺点

索引失效

在什么情况下适合建立索引

为什么用B+树做索引而不用B-树或红黑树

联合索引

什么是联合索引

命名规则

创建索引

索引类型

删除索引

什么情况下使用索引


索引

索引是什么呢?简而言之,索引就是一种高效找到数据的一种数据结构。

比如我们查字典,如果我们查每个字都从第一页开始翻,直到找到我们的目标为止的话,显然效率是十分低下的。所以便有了我们的拼音索引表,根据这个索引表,我们找每个字的时间就大大缩短了。

B Tree 原理

B-Tree

定义一条数据记录为一个二元组 [key, data],B-Tree 是满足下列条件的数据结构:

  • 所有叶节点具有相同的深度,也就是说 B-Tree 是平衡的;
  • 一个节点中的 key 从左到右非递减排列;
  • 如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的(所有 key ≥ keyi) 且(key ≤ keyi+1)。

查找算法:首先在根节点进行二分查找,如果找到则返回对应节点的 data,否则在相应区间的指针指向的节点递归进行查找。

由于插入删除新的数据记录会破坏 B-Tree 的性质,因此在插入删除时,需要对树进行一个分裂、合并、旋转等操作以保持 B-Tree 性质。

B+Tree

与 B-Tree 相比,B+Tree 有以下不同点:

  • 每个节点的指针上限为 2d 而不是 2d+1(d 为节点的出度);
  • 内节点不存储 data,只存储 key;
  • 叶子节点不存储指针。

顺序访问指针

一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 基础上进行了优化,在叶子节点增加了顺序访问指针,做这个优化的目的是为了提高区间访问的性能。

优势

红黑树等平衡树也可以用来实现索引,但是文件系统及数据库系统普遍采用 B Tree 作为索引结构,主要有以下两个原因:

(一)更少的检索次数

平衡树检索数据的时间复杂度等于树高 h,而树高大致为 O(h)=O(logdN),其中 d 为每个节点的出度。

红黑树的出度为 2,而 B Tree 的出度一般都非常大。红黑树的树高 h 很明显比 B Tree 大非常多,因此检索的次数也就更多。

B+Tree 相比于 B-Tree 更适合外存索引,因为 B+Tree 内节点去掉了 data 域,因此可以拥有更大的出度,检索效率会更高。

(二)利用计算机预读特性

为了减少磁盘 I/O,磁盘往往不是严格按需读取,而是每次都会预读。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,因此速度会非常快。

操作系统一般将内存和磁盘分割成固态大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点,并且可以利用预读特性,相邻的节点也能够被预先载入。

更多内容请参考:MySQL 索引背后的数据结构及算法原理

索引分类

特性 说明 InnoDB MyISAM MEMORY
B树索引 (B-tree indexes) 自增ID物理连续性更高,
二叉树,红黑树高度不可控
R树索引 (R-tree indexes) 空间索引    
哈希索引 (Hash indexes) 无法做范围查询  
全文索引 (Full-text indexes)    

B+Tree 索引

B+Tree 索引是大多数 MySQL 存储引擎的默认索引类型。

因为不再需要进行全表扫描,只需要对树进行搜索即可,因此查找速度快很多。除了用于查找,还可以用于排序和分组。

可以指定多个列作为索引列,多个索引列共同组成键。

B+Tree 索引适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。

如果不是按照索引列的顺序进行查找,则无法使用索引。

InnoDB 的 B+Tree 索引分为主索引辅助索引

主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。

辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。

哈希索引

InnoDB 引擎有一个特殊的功能叫 “自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。

哈希索引能以 O(1) 时间进行查找,但是失去了有序性,它具有以下限制:

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

全文索引

MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相等。查找条件使用 MATCH AGAINST,而不是普通的 WHERE。

全文索引一般使用倒排索引实现,它记录着关键词到其所在文档的映射。

InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。

空间数据索引(R-Tree)

MyISAM 存储引擎支持空间数据索引,可以用于地理数据存储。空间数据索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。

必须使用 GIS 相关的函数来维护数据。

索引的特点

  • 可以加快数据库的检索速度
  • 降低数据库插入、修改、删除等维护的速度
  • 只能创建在表上,不能创建到视图上
  • 既可以直接创建又可以间接创建
  • 可以在优化隐藏中使用索引
  • 使用查询处理器执行SQL语句,在一个表上,一次只能使用一个索引

索引的优点

  • 创建唯一性索引,保证数据库表中每一行数据的唯一性
  • 大大加快数据的检索速度,这是创建索引的最主要的原因
  • 加速数据库表之间的连接,特别是在实现数据的参考完整性方面特别有意义
  • 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
  • 通过使用索引,可以在查询中使用优化隐藏器,提高系统的性能

索引的缺点

  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
  • 索引需要占用物理空间,除了数据表占用数据空间之外,每一个索引还要占一定的物理空间,如果建立聚簇索引,那么需要的空间就会更大
  • 当对表中的数据进行增加、删除和修改的时候,索引也需要维护,降低数据维护的速度

索引失效

  • 如果MySQL估计使用全表扫秒比使用索引快,则不适用索引。

    例如,如果列key均匀分布在1和100之间,下面的查询使用索引就不是很好:select * from table_name where key>1 and key<90;

  • 如果条件中有or,即使其中有条件带索引也不会使用

    例如:select * from table_name where key1='a' or key2='b';如果在key1上有索引而在key2上没有索引,则该查询也不会走索引

  • 复合索引,如果索引列不是复合索引的第一部分,则不使用索引(即不符合最左前缀)

    例如,复合索引为(key1,key2),则查询select * from table_name where key2='b';将不会使用索引

  • 如果like是以 % 开始的,则该列上的索引不会被使用。

    例如select * from table_name where key1 like '%a';该查询即使key1上存在索引,也不会被使用如果列类型是字符串,那一定要在条件中使用引号引起来,否则不会使用索引

  • 如果列为字符串,则where条件中必须将字符常量值加引号,否则即使该列上存在索引,也不会被使用。

    例如,select * from table_name where key1=1;如果key1列保存的是字符串,即使key1上有索引,也不会被使用。

  • 如果使用MEMORY/HEAP表,并且where条件中不使用“=”进行索引列,那么不会用到索引,head表只有在“=”的条件下才会使用索引

在什么情况下适合建立索引

  • 为经常出现在关键字order by、group by、distinct后面的字段,建立索引。
  • 在union等集合操作的结果集字段上,建立索引。其建立索引的目的同上。
  • 为经常用作查询选择 where 后的字段,建立索引。
  • 在经常用作表连接 join 的属性上,建立索引。
  • 考虑使用索引覆盖。对数据很少被更新的表,如果用户经常只查询其中的几个字段,可以考虑在这几个字段上建立索引,从而将表的扫描改变为索引的扫描。

更多资料:MySQL索引背后的数据结构及算法原理

为什么用B+树做索引而不用B-树或红黑树

B+ 树只有叶节点存放数据,其余节点用来索引,而 B- 树是每个索引节点都会有 Data 域。所以从 InooDB 的角度来看,B+ 树是用来充当索引的,一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上。

  • 那么 MySQL如何衡量查询效率呢?答:磁盘 IO 次数

    • B- 树 / B+ 树 的特点就是每层节点数目非常多,层数很少,目的就是为了就少磁盘 IO 次数,但是 B- 树的每个节点都有 data 域(指针),这无疑增大了节点大小,说白了增加了磁盘 IO 次数(磁盘 IO 一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO 次数增多,一次 IO 多耗时),而 B+ 树除了叶子节点其它节点并不存储数据,节点小,磁盘 IO 次数就少。
    • B+ 树所有的 Data 域在叶子节点,一般来说都会进行一个优化,就是将所有的叶子节点用指针串起来。这样遍历叶子节点就能获得全部数据,这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而 B 树不支持这样的遍历操作。
  • B 树相对于红黑树的区别

    • AVL 树和红黑树基本都是存储在内存中才会使用的数据结构。在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘 IO 读写过于频繁,进而导致效率低下的情况。为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,接着旋转盘面找到数据所在的磁道,最后对数据进行读写。磁盘IO代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读写。根据磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B树可以有多个子女,从几十到上千,可以降低树的高度。
    • 数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次 I/O 就可以完全载入。为了达到这个目的,在实际实现 B-Tree 还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个 node 只需一次 I/O。

联合索引

什么是联合索引

两个或更多个列上的索引被称作联合索引,联合索引又叫复合索引。对于复合索引:Mysql 从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。

例如索引是key index (a,b,c),可以支持[a]、[a,b]、[a,b,c] 3种组合进行查找,但不支 [b,c] 进行查找。当最左侧字段是常量引用时,索引就十分有效。

命名规则

  1. 需要加索引的字段,要在 where 条件中
  2. 数据量少的字段不需要加索引
  3. 如果 where 条件中是OR关系,加索引不起作用
  4. 符合最左原则

创建索引

在执行 CREATE TABLE 语句时可以创建索引,也可以单独用 CREATE INDEX 或 ALTER TABLE 来为表增加索引。

ALTER TABLE

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

例如:

 ALTER TABLE table_name ADD INDEX index_name (column_list)
 ALTER TABLE table_name ADD UNIQUE (column_list)
 ALTER TABLE table_name ADD PRIMARY KEY (column_list)

其中 table_name 是要增加索引的表名,column_list 指出对哪些列进行索引,多列时各列之间用逗号分隔。索引名 index_name 可选,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE 允许在单个语句中更改多个表,因此可以在同时创建多个索引。

CREATE INDEX

CREATE INDEX 可对表增加普通索引或 UNIQUE 索引。

例如:

 CREATE INDEX index_name ON table_name (column_list)
 CREATE UNIQUE INDEX index_name ON table_name (column_list)

table_name、index_name 和 column_list 具有与 ALTER TABLE 语句中相同的含义,索引名不可选。另外,不能用 CREATE INDEX 语句创建 PRIMARY KEY 索引。

索引类型

在创建索引时,可以规定索引能否包含重复值。如果不包含,则索引应该创建为 PRIMARY KEY 或 UNIQUE 索引。对于单列惟一性索引,这保证单列不包含重复的值。对于多列惟一性索引,保证多个值的组合不重复。 PRIMARY KEY 索引和 UNIQUE 索引非常类似。

事实上,PRIMARY KEY 索引仅是一个具有名称 PRIMARY 的 UNIQUE 索引。这表示一个表只能包含一个 PRIMARY KEY,因为一个表中不可能具有两个同名的索引。 下面的SQL语句对 students 表在 sid 上添加 PRIMARY KEY 索引。 ​ ALTER TABLE students ADD PRIMARY KEY (sid)

删除索引

可利用 ALTER TABLE 或 DROP INDEX 语句来删除索引。类似于 CREATE INDEX 语句,DROP INDEX 可以在 ALTER TABLE 内部作为一条语句处理,语法如下。

 DROP INDEX index_name ON talbe_name
 ALTER TABLE table_name DROP INDEX index_name
 ALTER TABLE table_name DROP PRIMARY KEY

其中,前两条语句是等价的,删除掉 table_name 中的索引 index_name。

第3条语句只在删除 PRIMARY KEY 索引时使用,因为一个表只可能有一个 PRIMARY KEY 索引,因此不需要指定索引名。如果没有创建 PRIMARY KEY 索引,但表具有一个或多个 UNIQUE 索引,则 MySQL 将删除第一个 UNIQUE 索引。

如果从表中删除了某列,则索引会受到影响。对于多列组合的索引,如果删除其中的某列,则该列也会从索引中删除。如果删除组成索引的所有列,则整个索引将被删除。

什么情况下使用索引

  1. 为了快速查找匹配WHERE条件的行。
  2. 为了从考虑的条件中消除行。
  3. 如果表有一个multiple-column索引,任何一个索引的最左前缀可以通过使用优化器来查找行。
  4. 查询中与其它表关联的字,字段常常建立了外键关系
  5. 查询中统计或分组统计的字段
    • select max(hbs_bh) from zl_yhjbqk
    • select qc_bh,count(*) from zl_yhjbqk group by qc_bh

猜你喜欢

转载自blog.csdn.net/qq_37410328/article/details/83716071