MySQL是对用户的数据进行管理的,而数据都保存在磁盘中,MySQL对数据进行管理需要先将数据从磁盘读取到内存中,再将修改了的数据,刷新到磁盘中。然而,这是IO操作,效率是比较低的。
并且当数据量比较大时,当查询数据时,由于内存无法全部保存数据,只能将数据分批次读取上来,这样会导致IO次数增加。
索引是MySQL中提高查询数据的一种方式。但是查询数据的提高是以插入,更新,删除的速度为代价的。
所以索引的价值在于提高海量数据的查询速度。
下面来介绍索引是如何提高查询效率的,首先我们来了解一下磁盘,并且为什么磁盘操作会这么慢。
磁盘的一个盘片:
所以找到一个数据库文件,需要定位到保存文件的扇区。
磁盘定位文件的扇区:
先定位盘面,也就确定了磁头。在确定柱面(磁头旋转到柱面处),再确定好扇区(盘片旋转,使得磁头指向对应扇区)。
这种磁盘数据定位方式叫做CHS。但是实际系统软件使用的并不是CHS(硬件是),使用的是LBA,一种线性地址,可以想象成虚拟地址和物理地址(可以抽象成一个大数组),系统将LBA的地址最后转化成CHS,交给磁盘进行数据读取。
在硬件层面上,我们已经可以定位一个扇区,那么在系统软件层面上,我们也是按一个扇区的大小来读进行IO交互吗?
答案是并不是。
磁盘随机访问和连续访问:
随机访问:是本次IO给出的扇区的地址和上一次IO给出的扇区地址不连续,需要重新定位盘片,磁道和扇区。
连续访问:是本次IO给出的扇区的地址和上一次IO给出的扇区地址连续,不需要过多的定位。
因此,连续访问的效率比随机访问的效率高。
MySQL作为一款应用软件,可以想象成一个特殊的文件系统。它有着更高的IO场景,为了提高IO效率,MySQL与磁盘交互的基本单位是16KB。
用指令查看:
磁盘硬件设备的基本单位是512字节,操作系用户与磁盘交互的基本单位是4KB,称为一个page。MySQL和磁盘进行交互的基本单位是16KB,在MySQL中也被称为page,下面讨论的是MySQL的page。
注意:MySQL与磁盘交互(IO)每次是一个Page,也就是16KB。不是多个Page。
总结:
画一个图来理解 一下:
建立测试表:
我们发现,我们主键插入的顺序并不是有序的,但是在表中,确变成了有序的,这是谁做的呢?这样有什么好处呢?
实际上这是因为MySQL的索引结构,要求的。好处下面介绍。
说明:如果这里没有主键,插入什么顺序,表中就是什么顺序。这说明,索引需要和特定的设定有关。
MySQL中的数据文件可能有一个或者多个Page构成,而MySQL是管理数据的。所以MySQL中会有很多Page。MySQL需要对page进行管理,就需要先描述后组织。
不同的Page在MySQL中,都是16KB,同一文件的page使用双向链表组织起来。而数据都保存在page中,以链表的形式组织在page中。
如果有主键,MySQL会按照主键给我们的数据进行排序。
但是,当数据量很大时,说明,一个page中保存的数据量很多。而数据在page中是以链表的形式组织的。查找数据时,一定也是线性查找。比如:数据保存在很后面,效率也很低。
于是:MySQL在page中增加了一个类似于目录的结构,来将数据链表分成多段。目录结构中保存的是该段链表中的最小Key值和该结点的地址。如下:
于是在单个page中查找某个值时,先查询目录,找到对应链表段,再遍历链表段,找到数据。这样会大大提高效率。
比如:上面数据,查找id=5的数据。先在目录中查找,找到目录key值等于4的后,找到链表地址,遍历该段链表,即可找到5.寻找次数是4次。而如果没有目录,直接遍历链表,查找的次数是5次。但是由于上面的例子数据量不是很大,当数据量很大,目录跨度很大时,效率会有明显的提高。
MySQL中,Page的大小是固定的16KB。当一个文件数据很大时,需要由多个Page来构成。同一文件的多个Page使用双向链表组织起来。
在单表不断被插入的情况,MySQL会在一个Page容量不足的情况下,自动开辟新的Page来保存新的数据,然后通过指针方式,将所有page组织起来。
这样我们查找某个数据时,需要遍历整个双向链表,并且每一个page还需要遍历。
虽然遍历一个page的效率有所提高,但是,遍历整个链表,并且需要将每一个遍历的page从磁盘加载到内存,这也就意味着依旧需要进行大量的IO。这样会效率仍然会收到影响。
于是按照上面的思想,MySQL对每一个Page也添加了一个目录。
于是有了下面的结构:
存在一个目录页来管理保存数据的page。先在目录页中比较,找到需要访问的保存数据的page,通过目录保存的指针找到保存数据的page。在在page中寻找数据。
但是当文件数据的page过多时,也就是双向链表过长时。管理双向链表的目录页也会过长。于是,可以通过增加了目录页来管理下一层的目录页,如此循环。
从上面可以看出,**索引保存数据的结构采用的是B+树。**由于上面的例子数据量太少,看不出有什么明显的差别。当数据量很大,并且,当一个page中保存的目录很多时,效率会明显提高。
这样随便找一个id,需要查询的page数一定会减少,也就意味着IO的次数减少了。
总结:
说明:
MySQL每次和磁盘交互大小是一个Page,当查找到数据,将数据拿到buffer pool中后,也会将其组织成B+树的形式。可以理解是,为了方便查找。
MySQL是管理用户数据的软件,数据保存在磁盘中。MySQL增删查改数据需要将数据拿到内存中,需要进行IO。而MySQL和磁盘每次交互的大小是一个page(16KB)。当数据量很大时,会导致IO次数变得很多,效率会降低。
索引是MySQL为了提高查询数据效率的一种方式。
实现是以page大小为结点构建一颗B+树,叶子结点保存数据,非叶子结点保存孩子结点的地址和最小键值,也只结点组织成了链表形式。
B+树的整体优势是,高度低,IO次数少。叶子结点组织成链表形式,方便范围查找。
非聚簇索引:数据文件和索引文件分离。典型代表是MyISAM存储引擎。
MyISAM:同样是用B+树作为索引结构。叶子结点保存的是数据的地址或者路径。下图为MyISAM的主索引,col1为主键:
用主键建立的索引为主索引。
通过查询B+树,最终得到数据的地址或者路径。再通过地址或者路径找到数据。
使用MyISAM存储引擎建立一张表:
当然,可能用户在建立表是没有设定主键,并且,使用其它信息列建立索引。这种缩影可以叫做辅助索引。
MyISAM的辅助索引和主索引建立没有差别,主要差别是主索引保存的键值不能重复。辅助索引保存的键值可以重复。
下图是以Col2建立的辅助索引。
聚簇索引:数据文件和索引文件是一个文件。典型是innodb存储引擎。
Innodb,使用的是B+树作为索引结构,叶子结点保存的就是数据。
下图是以主键建立的索引结构,称为主索引。
通过查询B+树,找到叶子结点就找到了数据。
用innodb存储引擎创建一张表:
innodb同样可以不使用主键建立表,也叫做辅助索引。但是,innodb的辅助索引叶子结点保存的是对应主键值。
查找数据向通过辅助索引找到主键值,再通过主键值,在主索引中找到数据。
说明:Innodb要求表中必须有主键,因为Innodb索引文件(数据文件),最后必须按照主键来找到是数据。如果用户没有显示设置主键,MySQL会自动选择一个可以唯一标识数据记录的列作为主键,比如:自增字段。如果不存在这种列,MySQL会为Innodb表自动生成一个隐含字段作为主键。这个字段占6字节,类型为长整型。
索引分为:
主要是设置主键。
在创建表时,在字段后面,直接加上primary key。
create table test2( id int primary key, name varchar(20));
在创建表时,指定某列或者某几列为主键。
create table test3( id int, name varchar(20), primary key(id));
创建表后增加主键。
create table test4( id int, name varchar(20));
alter table test4 add primary key(id);
主键索引特点:
主要是创建唯一键。
在创建表时,给字段加上unique属性。
create table test5( id int primary key, name varchar(20) unique);
在创建表时,指定某列或者某几列为唯一键。
create table test6( id int primary key, name varchar(20), unique (name));
创建表后增加唯一键。
create table test7( id int primary key, name varchar(20));
alter table test7 add unique(name);
唯一索引特点:
在创建表时,指定某列为普通索引
create table test8( id int primary key, name varchar(20), index(name));
在创建表后,指定某一列为普通索引
create table test9( id int primary key, name varchar(20));
alter table test9 add index(name);
创建表后,创建一个索引名为index_name的索引
create table test10( id int primary key, name varchar(20));
create index index_name on test10(name);
普通索引特点:
对文章字段或者有大量文字的字段进行检索。
使用全文索引必须使用MyISAM存储引擎,默认支持英文,不支持中文。如果对中文进行全文索引,可以使用sphinx的中文版(coreseek)。
创建全文缩影:
在创建表时,指定某列为全文索引。
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT (title,body)
)engine=MyISAM;
插入一些值:
并没有使用全文索引,而是将数据全部遍历查找。
可以使用explain工具查看,是否使用索引。
alter table 表名 drop primary key;删除主键。
第一种方法:
alter table 表名 drop index 索引名;
索引名是show keys from 表名中的key_name 字段。
alter table test5 drop index name;
第二种方法:
drop index 索引名 on 表名
索引提高了查询的效率,但是,降低了插入,删除和修改的效率。
多个字段作为索引。
比如:主键,一个表中只能有一个。如果,设置多个主键,该表中也只有一个主键,是所有主键组合起来,充当这个表的主键。
在主索引中,关键字就会使所有主键的组合。
使建立在复合主键的基础上。查询的字段正好在关键字里,不会再查询到也直接点,直接返回。相当于覆盖率往叶子系欸但查找的过程。
如果索引关键字是"id,name",如果使用select * from where name = ‘…’,不能进行查找,因为name再关键字的右边。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_43842093/article/details/121667725
内容来源于网络,如有侵权,请联系作者删除!