Mysql(1)--SQL优化基础知识

参考:《MySQL技术内幕 InnoDB存储引擎 第2版》、

一、mysql逻辑结构

image-20210329105217103

mysql的体系结构大致可以分为Server层和存储引擎层两部分:

  • Server层:包括连接器,查询缓存,分析器,优化器,执行器等包含Mysql的大多数核心服务,以及所有的内置函数
  • 存储引擎层:负责数据的存储和提取,其架构模式是插件式的,从Mysql5.5开始默认的存储引擎为InnoDB

下面分别介绍Server层相关的组件:

  • 连接器:负责管理连接,权限认证的工作比如说管理员账号与普通账号之间的权限不同
  • 查询缓存:Mysql在进行查询的操作的时候会先来到查询缓存,判断之前是否执行过该语句,但是一般不推荐使用查询缓存,因为每次进行一个表的更新操作,该表上的缓存就失效了,从mysql8.0开始这个功能被取消了
  • 分析器:分析器要做的工作时进行语法分析,判断该条语句是做什么操作的
  • 优化器:经过分析器,Mysql知道该语句是做什么工作的吗,而优化器是在表中有多个索引的时候,决定使用哪一个索引或者其他的优化操作
  • 执行器:Mysql通过分析器知道了要做什么,通过优化器知道了该怎么做,那么执行要做的工作就是真正的执行这个语句,与存储引擎之间进行交互

如上的顺序其实也是执行一条查询语句,mysql做的事情,就像流水线一样下来

二、几种常见的存储引擎比较

  • InnoDB:InnoDB存储引擎是Mysql的默认存储引擎。InnoDB存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全。但是对比MyISAM的存储引擎,InnoDB写的处理效率差一些,并且会占用更多的磁盘空间以保留数据和索引。
  • MyISAM :MyISAM 不支持事务、也不支持外键,其优势是访问的速度快,对事务的完整性没有要求或者以SELECT、INSERT为主的应用基本上都可以使用这个引擎来创建表 。
  • MEMORY:Memory存储引擎将表的数据存放在内存中。每个MEMORY表实际对应一个磁盘文件,格式是.frm ,该文件中只存储表的结构,而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。MEMORY 类型的表访问非常地快,因为他的数据是存放在内存中的,并且默认使用HASH索引 , 但是服务一旦关闭,表中的数据就会丢失
  • MERGE:MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,MERGE表本身并没有存储数据,对MERGE类型的表可以进行查询、更新、删除操作,这些操作实际上是对内部的MyISAM表进行的。

InnoDB与MyISAM 之间的比较:

  • InnoDB是目前默认的存储引擎,而MyISAM是在mysql5之前的
  • 在事务方面,InnoDB是支持事务的,而MyISAM是不支持事务的,MyISAM在系统崩溃后恢复起来难受
  • 在锁方面,InnoDB是行级锁,而MyISAM支持的是表锁,所以在效率方面InoDB的效率要好点
  • 在外键方面,InnoDB支持外键,而MyISAM不支持外键
  • 在聚族索引方面,都是使用B+数作为索引,但是MyISAM索引和文件是分离的,InnoDB的索引和数据时绑定在一起的,所以InnoDB一定要有主键,如果没有主键则会选取一个作为主键

三、索引

1.索引是什么?

简单来说,索引就是一种数据结构。索引是帮助数据库MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

2. 索引与B+树

回想起生活中的例子,例如查字典,查找单词mysql,是不是先去找m,然后在依次查找,如果对于a-z这26个字母,使用顺序查找的话,那么要查找13次才可以找到,如果使用二分查找的话,在较少的次数内就可以找到,但是我们实际上查找mysql这个单词,是不是检索索引,通过索引来快速定位m这个位置,那么如果使用多路查找树呢?那不是还要更快?图书的目录,火车站的车次表等等都是通过不断的缩小目标数据的范围来筛选出最终的结果。

数据库也是一样的,数据库的操作大都是查询,但是数据库的数据保存在磁盘上,学过计算机组成原理就明白,磁盘的操作很耗时!访问磁盘的成本大概是访问内存的十万倍左右!所以对于数据库中的数据,不可使用AVL树,因为它的不平衡性可能会导致大量的io操作,使得性能急速下降,这个时候就出现了B树(具体可看数据结构与算法分析Java语言描述中B树这一小节),B+树(B树的一个变形)是高度可控的多路搜索树。使得查找数据时将磁盘io树控制在一个很小的数量级

3.B+树

Mysql中的索引使用的是B+树,B+树是B树的一个变形,BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下:

  • 树中每个节点最多包含m个孩子。
  • 除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子。
  • 若根节点不是叶子节点,则至少有两个孩子。
  • 所有的叶子节点都在同一层。
  • 每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1] <= n <= m-1

B+树

B+Tree为BTree的变种,B+Tree与BTree的区别为:

1). n叉B+Tree最多含有n个key,而BTree最多含有n-1个key。

2). B+Tree的叶子节点保存所有的key信息,依key大小顺序排列。

3). 所有的非叶子节点都可以看作是key的索引部分。

4.Mysql中的B+树

参考链接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2mCf0b9S-1616994232027)(C:\Users\VSUS\Desktop\笔记\MySQL\sql图片\03.jpg)]

如上图,是一颗b+树,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非叶子节点只不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。

b+树的查找过程:

如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

四、索引的语法

4.1 索引的分类

1) 单值索引 :即一个索引只包含单个列,一个表可以有多个单列索引

2) 唯一索引 :索引列的值必须唯一,但允许有空值

3) 复合索引 :即一个索引包含多个列

4.2 创建索引

语法:

CREATE 	[UNIQUE|FULLTEXT|SPATIAL]  INDEX index_name 
[USING  index_type]
ON tbl_name(index_col_name,...)


index_col_name : column_name[(length)][ASC | DESC]

例如:为tb_seller表的name字段创建单值索引:

mysql> create index idx_tb_seller_name on tb_seller(name);
4.3 查看索引
show index from [table_name]

例如:查看上面建的索引

show index from tb_seller;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cHbIC1qo-1616994232031)(C:\Users\VSUS\Desktop\笔记\MySQL\sql图片\04.png)]

可以看到有两条索引,这是因为在建表的时候创建了主键,主键会被默认设置为索引,可以看到key_name为PRIMARY,并且Non_unqiue为0代表这个字段不能重复,而且是使用BTREE数据结构。(\G是为了在Linux上更好的显式)

  • Table:索引所在的表名

  • Non_unique:非唯一·的索引,主键的索引为0,因为主键只能唯一

  • Key_name:索引的名字,可以通过这个名字来删除索引

  • Seq_in_index:索引中该列的位置,例如联合索引 idx_a_c(a,c) 对于列a,Seq_in_index值为1,对于列c,Seq_in_index值为2

  • Column_name:列名

  • Collation:列以何种方式存储在索引中,B+树的索引总是A

  • Cardinality:非常关键的一个参数,表示索引中唯一值的数目的估计值,这个值应尽量接近1,如果非常小,那么需要考虑是否有必要创建这个索引。例如:对于性别字段,进行查询的时候也许得到的结果是整个表的50%,那么建立索引没有太大的必要,但是如果姓名字段,整张表都不重复,那么建立索引是很有必要的,在后面索引失效的时候会用到这个值

  • Sub_part:是否是列的部分被索引

  • 关键字如何被压缩

  • Null:是否可以有null值

  • Index_type:索引类型,B+类型显示为BTREE

  • Comment:注释

4.4 删除索引
drop index index_name on table_name;

例如:删除上面创建的索引

mysql> drop index idx_tb_seller_name on tb_seller;
4.4 删除索引
drop index index_name on table_name;

例如:删除上面创建的索引

mysql> drop index idx_tb_seller_name on tb_seller;

猜你喜欢

转载自blog.csdn.net/weixin_44706647/article/details/115298641