数据库中的索引

07-21 1683阅读

一、索引的好处

首先,我们先看一个例子。

数据库中的索引

再上图中我们有一个8000000数据的表叫EMP,一开始我们没有主键查找一个值花了4.07秒,若加上了主键花的时间小于0.01秒,所以在大量数据中查找有没有索引就尤为重要。

索引:提高数据库的性能,索引是物美价廉的东西了。不用加内存,不用改程序,不用调sql,只要执行正确的 create index ,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插入、更新、删 除的速度为代价的,这些写操作,增加了大量的IO。所以它的价值,在于提高一个海量数据的检索速度。

二、认识磁盘

数据库中的索引

数据库中的索引

在磁盘中找数据:磁头(head,决定数据在哪一面)-> 磁道(track)柱面(cylinder)(决定在面上的哪个同心圈)-> 扇区(sector,决定在哪个区)

上述在硬件中查找数据方式:CHS

在操作系统中查找方式:LBA    虚拟地址->物理地址

系统读磁盘以块为单位,基本单位4KB

随机访问:本次IO的扇区地址与上次IO地址不连续,这样磁头两次IO之间要有较大的移动才能读写数据。

连续访问:本次IO的扇区地址与上次IO地址连续。

当然操作系统会对地址进行排序,尽量以连续方式进行IO

三、MySQL与磁盘交互的基本单位

数据库中的索引

数据库中的索引

上图中InnoDB中的page大小就是16KB

MySQL 中的数据文件,是以page为单位保存在磁盘当中的。

MySQL 的 CURD 操作,都需要通过计算,找到对应的插入位置,或者找到对应要修改或者查询的数据。 而只要涉及计算,就需要CPU参与,而为了便于CPU参与,一定要能够先将数据移动到内存当中。

所以在特定时间内,数据一定是磁盘中有,内存中也有。后续操作完内存数据之后,以特定的刷新策略,刷新 到磁盘。而这时,就涉及到磁盘和内存的数据交互,也就是IO了。

而此时IO的基本单位就是Page。 为了更好的进行上面的操作, MySQL 服务器在内存中运行的时候,在服务器内部,就申请了被称为 Buffer Pool 的的大内存空间,来进行各种缓存。其实就是很大的内存空间,来和磁盘数据进行IO交互。 为了更高的效率,一定要尽可能的减少系统和磁盘IO的次数。

四、page在MySQL中的理解

1、建模

上面我们提到MySQL中有大量数据存放在page中,所以MySQL中有大量的page,要把他们管理起来就要先描述再组织,在Buffer Pool中建模。

struct page

{

        struct page* prev;

        struct page* next;

        char buff[NUM];

}

2、为什么要用page进行IO交互

预加载机制有效利用局部性原理提高IO效率。

预加载机制:单个page大小16KB,可以加载大量数据。

局部性原理:加载周边数据,预测用户下次查找地址,减少IO次数,提高效率。

五、InnoDB中的索引结构

但是上述的page组织结构存在很大问题,由于是链表形式链接一个个page,导致查询结果是O(N),是绝对不能接受的,所以引入页目录。然而我们知道数据的组织形式是page内部存有数据,page外部再用数据结构连接,所以要想提高效率就要从这两方面入手。

1、理解单个page

数据库中的索引

由于单个page中有大量数据,那么我们在其中设置目录就能范围查找,加快速度。

所以我们理解了为什么无序插入带有主键的表,出来的主键是有序的,那是因为只有有序才能在目录查找时是有意义的。

2、多页情况

数据库中的索引

这就像是B+树的结构,非叶子节点不存数据,存放叶子节点的索引,只有在最后一层才存放完整数据,并且用链表链接(上图是错的,非叶子节点是没有链表把page链接在一起的)

细节

(1)非叶子节点不存数据,可以储存更多的目录,管理更多的page

(2)查找时只要加载部分目录到内存即可完成查找,减少IO次数。

六、InnoDB与MyISAM引擎

MyISAM最大的特点就是索引page和数据page分离,叶子结点只有数据地址,是非聚簇索引。

而InnoDB是将数据和索引放一起模式聚簇索引。

值得一提的是在InnoDB中创建辅助索引,叶子结点并没有数据,只有主键值,然后用主键值在主键索引树中查到数据,叫做回表查询。

那为什么不放数据呢?没必要存多份数据,太浪费空间。

具体介绍可查看我的文章http://t.csdnimg.cn/D53Du

截图以供参考

数据库中的索引

七、索引操作

1、创建主键索引

(1)create table user1(id int primary key, name varchar(30));

(2)create table user2(id int, name varchar(30), primary key(id));

(3)create table user3(id int, name varchar(30));

          alter table user3 add primary key(id);

数据库中的索引

主键索引的特点

(1) 一个表中,最多有一个主键索引,当然可以使复合主键 主键索引的效率高(主键不可重复) (2)它的值不能为null,且不能重复。

(3)主键索引的列基本上是int

2、创建唯一索引

(1) create table user4(id int primary key, name varchar(30) unique);

(2)create table user5(id int primary key, name varchar(30), unique(name)); 

(3)create table user6(id int primary key, name varchar(30));

          alter table user6 add unique(name);

数据库中的索引

唯一索引的特点

(1)一个表中,可以有多个唯一索引 查询效率高。

(2)如果在某一列建立唯一索引,必须保证这列不能有重复数据。

(3)如果一个唯一索引上指定not null,等价于主键索引。

3、创建普通索引 

(1)create table user8(id int primary key, name varchar(20), email varchar(30), index(name));

(2)create table user9(id int primary key, name varchar(20), email varchar(30));

           alter table user9 add index(name); 

(3)create table user10(id int primary key, name varchar(20), email varchar(30));

          create index idx_name on user10(name);创建一个索引名为 idx_name 的索引

普通索引的特点

(1)一个表中可以有多个普通索引。

(2)如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引。

4、删除索引

(1)删除主键索引

alter table 表名 drop primary key;

(2)删除其他索引 

alter table 表名 drop index 索引名; 索引名就是show keys from 表名中的 Key_name 字段

drop index 索引名 on 表名 ;

数据库中的索引

数据库中的索引

5、查询索引

(1)show keys from 表名;

(2)show index from 表名;

(3)desc 表名;

6、全文索引

explain sql语句;    用来解释要怎么执行sql语句

举例

数据库中的索引

上图是创建了一个文本。

数据库中的索引

当我们用传统的where子句查询时发现key:NULL,说明没有用到索引查询,效率必然低。

语法

select * from 表名 where match (全文索引名) against ('关键字');

数据库中的索引

这时key:title就表示用title充当全文索引来查找关键字'database'

7、复合索引

语法

alter table 表名 add index (索引名1,索引名2....)

会以索引名1来创建B+树

数据库中的索引

上图我们就把name和email当做复合索引

我们知道用普通索引找一个值会找2次,但是用复合索引,并且索引绑定了我们要查找的值,我们就可以只找一次。

例如,index(name, email)后,我们要找张三的邮箱,只要name找到张三就行,返回绑定的邮箱数据,而这种未通过主键找到email的行为就是索引覆盖,覆盖的是主键。

在上述例子中,我们可以拿“张三”或“张三+邮箱”来查找数据,但是不能只拿“邮箱”查找数据,这就是​​​​​​​索引的最左匹配原则。

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]