且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

MySQL之索引

更新时间:2022-10-02 20:24:39

1.关于查询缓存


直接看2个例子:


MySQL之索引



MySQL之索引


可以发现,第一次执行SQL的结果会缓存起来,第二次执行同样的SQL的时候,会快很多。


那能不能在第一次执行的时候,就非常快?


物美价廉:使用索引。



2.关于索引



  • 主键索引


注意,当一个表的字段为primary key的时候,会自动成为主键索引的。


MySQL之索引


【利用show index(es)/keys from table 可以查看一张表上的索引】

在索引列上进行查询一般而言是非常快的,例如:


MySQL之索引


注意这张表是非常大的(+300W),但是查找一条记录的时间几乎为0.



  • 普通索引


就是在一个普通列上进行创建。



  • 全文索引


比如要在一片文章中进行关键词搜索。适用于myisam引擎类型的表。


创建全文索引方法:


fulltext(col1,col2,...)


要想适用全文索引的话,不可以使用select * from user where name like '%keyword%'的方式。


使用方法: match(col1,col2,...) against 'keyword'



在实际开发中,我们经常需要知道一条SELECT语句到底是否使用了索引,MYSQL会怎样执行,我们可以使用EXPLAIN命令来查看,从而帮助我们优化SQL结构。举例如下:


MySQL之索引


重点注意一下:

id              MYSQL查询序列号

select_type     有simple/union/subquery...

type            扫描的方式  【ALL代表全表扫描,system表仅有一行,const最多有一个匹配行】

possible_keys 可能使用到的索引

key           实际上使用的索引

key_len       使用索引的长度。这在复合索引,也就是多列索引中用于判断哪些索引有效使用,哪些索引没有被使用【最左前缀原理进行调整使用索引的策略】

rows            表示估算出来的结果集行数

extra            SQL语句的额外信息【using where 表示不用读取表中所有信息,仅通过索引就可以获取所需数据、using temporary 一些group by order by 的操作要使用临时表】



通过EXPLAIN命令的帮助,我们可以来调整SQL,调整完SQL后,其实我们可以利用:

show profiles;

来分析调整前后SQL的执行时间



3.索引原理分析

mysql对索引的定义为:


帮助MYSQL高效获取数据的一种数据结构。



  • 行,表,文件


MySQL之索引


分析:

A.行存储在文件中。

B.行,表都是数据库的概念,操作系统并不知道这些逻辑。

C.MYSQL的MYISAM存储引擎会将一个表的数据存放至一个文件,而在默认情况下INNODB,

则会不同表的数据都会存储至一个文件。

D.每个文件可以划分为页。比如上图,就划分了5个页。

E.要添加数据时,MYSQL会在最后一页的最后一行插入数据,如果最后一页已经满了的话,

就需要新生成一页。

F.如上图,每个页里面都有空隙,那么这是怎么造成的呢?

根据E,肯定不是添加数据导致的。而是删除数据导致的。也就是说,删除导致了页的碎片。

那么为什么MYSQL不在添加的时候自动去填充这种空隙呢?如果一张表很大,

MYSQL每次添加数据都需要从上到下去找空隙,那么这就会有很大的延时。

G.一个页能有多少行?

比如一个页的大小为4KB,一行记录占用90字节的话,那么4*1024/90=45,也就是说

大概一页可以放置45条数据。页的大小是和操作系统和数据库相关的。

H.页是I/O的基本单位。

数据库不可能指示操作系统去拿到某些记录或者拿到几个字节的数据,只能告诉去加载

哪些页至内存,然后数据库在页中找到想要的数据。也就是说,一条记录应该由  

页标示 + 行标示  共同构成这条记录的唯一标示。



  • 索引是如何工作的?


如果一张表很大,有几百万行,每次都使用顺序逐行查找的话,势必效率低下。

而索引,这种数据结构,提供了查找表的另外一种方式。


看一个简化版的MYSQL索引:

【构建在上面图中表的no列】


MySQL之索引


A.索引的数据结构表现形式为一个多节点的树

B.有一个根节点

C.节点内的值是有序的

D.可以看到根节点的44的P1指向的节点的值都小于等于44.其实其他的节点

都是这样的。

E.节点中的指针PX,要么指向下一个节点,如P3,要么指向表中的记录,如P6.

对于P6这种指向表中记录的节点即为叶子

F.叶子是链接的,也就是说一个叶子指向下一个叶子

G.其实P6相当于  页标示 + 行标示



  • 索引查找举例分析:


案例一:利用索引查找no=39的所有行


第一步,从根节点开始,此时根成为活动节点

第二步,判断活动节点是不是叶子,如果不是叶子,继续  第三步  ; 否则 继续 

        第四步

第三步,由于39<44,因此P1所指向的节点成为活动节点,继续  第二步

第四步,在活动节点中查找值,取出指针,也就是 这个值所在页的标示

第五步,数据库指示操作系统加载这些页,然后再在这些页中找到no=39的行


可见,查找特定的值的所有行,MYSQL利用索引,并不需要浏览所有行,可以快速找到。



案例二:获取按照no排序的所有行


直接查找叶子,先获取P6的所有页,然后是P7的所有页。

由于叶子后面还有叶子,因此下一个叶子继续上面的过程。


no=2的时候,需要取第二页

no=6的时候,需要取第一页

no=7的时候,需要取第三页

no=8的时候,需要取第四页

no=27的时候,需要取第二页

...


可以发现,由于文件中的行是没有顺序的,那么导致有些页必须多次获取,这会增加

处理时间。(内存中的页的个数是有限的,很可能有些页已经不在内存中,因此必须

重新从硬盘获取页)


为了加快这一过程,就必须文件中的行是有序存放的,那么就可能每个页只需要获取

一次,比如no=2在X页中,那么no=6就不需要再次获取页了,因为正确的页已经存在内存

中了,MYSQL是理解这一点的。

【上面的就是聚集索引的概念】




4.索引小结


  • insert,update,delete的时候,MYSQL是需要维护索引树


  • 上面图中的叶子的指针可能指向一行,也可能指向多行


如果no是主键,那么显然一个no只能有一条记录,那么指针所指向的只有一条记录。

如果我们在name上建立索引,由于name并非唯一的,那么指针会指向多个。


  • 索引的节点就像是表中的行,是需要占用物理空间的


本文转自zfz_linux_boy 51CTO博客,原文链接:http://blog.51cto.com/zhangfengzhe/1575893,如需转载请自行联系原作者