mysql结构与执行流程

MySql大体结构与执行流程

  1. mysql大体结构
    1.1 结构介绍
    简化版mysql结构,如下图:

在这里插入图片描述

MySQL逻辑架构整体分为三层:

  1. 客户端:并非MySQL所独有,诸如:连接处理、授权认证、安全等功能均在这一层处理
  2. 核心服务:包括查询解析、分析、优化、缓存、内置函数(比如:时间、数学、加密等函数),所有的跨存储引擎的功能也在这一层实现:存储过程、触发器、视图等
  3. 存储引擎:负责MySQL中的数据存储和提取,和Linux下的文件系统类似,每种存储引擎都有其优势和劣势,中间的服务层通过API与存储引擎通信,这些API接口屏蔽不同存储引擎间的差异

详细版mysql结构

在这里插入图片描述
组成部分:

  1. 连接池组件
  2. 管理服务和工具组件
  3. Sql接口组件
  4. 查询分析器组件
  5. 优化器组件
  6. 缓冲组件
  7. 插件式存储引擎(与其他数据库的主要区别)
  8. 物理文件

MySQL数据库区别与其他数据库最重要的一个特点就是期插件式的表存储引擎,mysql插件式的表存储引擎结构提供了一系列标准的管理和服务支持,这些标准与存储引擎本身无关,可能是每个数据库系统本身都必须的,例如SQL分析器和优化器等,而存储引擎是底层物理结构的实现,每个存储引擎开发者可以按照自己的意愿来进行开发,需要特别注意的是,存储引擎是基于表的,而不是数据库

1.2 体系结构详细
mysql的体系结构可以分为两层,mysql server层和存储引擎层,在mysql server层中又包括连接层与sql层。

  1. 连接层

       客户端获取应用程序通过接口(如:ODBC,JDBC)来连接MySQL,最先连接处理的就是连接层,连接层
       包括通信协议,线程处理,用户名密码认证三个部分,通信协议负责检测客户端版本是否与服务端
       兼容,线程处理是指每一个连接请求都会分配一个对应独立的线程,用户名密码认证创建的账号和
       密码,以及host主机授权是否可以连接到mysql服务器
    
  2. sql层

       sql层包含权限判断,查询缓存,解析器,预处理,查询优化器,缓存和执行计划;
       1)权限判断可以通过审核用户有没有访问某个库,某个表,或者表里某行的权限。
       2)查询缓存通过query cache进行操作,如果数据在query cache中,则直接返回结果给客户端
       3)查询解析器针对sql语句进行解析,判断语句是否正确,并生成解析器
       4)预处理器解决解析器无法解析的语义
       5)优化器对sql语句进行改写和相应的优化,例如:对连接表重排序,对外链接转内连接,代数等价
       法则,计算和减少常量表达式,自查询优化,早期终结,相等传递等,并生成最优的执行计划,然后就可以调用程序的API接口,通过存储引擎层访问数据;
    
  3. 存储引擎层

    Mysql 数据库的核心就在于存储引擎;

    Mysql数据库是开源的,所以用户可以根据mysql预定义的存储引擎接口编写自己的存储引擎,如果对现有存储引擎的性能或功能不满意,可以通过修改源码来得到想要的特性

    存储引擎可以分为mysql官网存储引擎和第三方存储引擎,innodb存储引擎早期就是第三方存储引擎,后来被oracle收购,同时也是mysql数据量OLTP在线事务处理应用最广泛的存储引擎。

    3.1 innodb存储引擎
         innodb存储引擎支持事务,其设计目标主要面向在线事务处理的应用,其特点是行锁设计,支持外
         键,并支持类似于Oracle的非锁定读,既默认读取操作不会产生锁,从mysql数据库5.5版本开始,
         innodb存储引擎是默认的存储引擎。
         innodb存储引擎将数据放在一个逻辑表空间中,这个表空间就像黑盒一样由innodb存储引擎自身进
         行管理,从mysql4.1版本开始,他可以将每个innodb存储引擎的表单独存放到一个独立的ibd文件
         中,此外,innodb存储引擎支持用裸设备来建立其表空间。
         innodb存储引擎通过使用多版本并发控制(MVCC)来获得高并发性,并且实现了sql标准的4种隔离级别,默认为RR级
         别,同时,使用一种被称为next-key locking的策略来避免幻读现象的产生,除此
         之外,innodb存储引擎还提供了插入缓存,二次写入,自适应hash索引,预读等高性能和高可用的
         功能。对于表中的数据存储,innodb存储引擎采用聚集的方式,因此每张表的存储都是按主键的顺
         序进行存放,如果没有显示在表定义时指定主键,innodb存储引擎会为每一行生成一个6字节的
         ROWID,并以此为主键。
     
    3.2 myisam存储引擎
         myisam存储引擎不支持事务。支持全文索引,主要面向一些OLAP数据应用,mysql5.5版本之前
         myisam存储引擎是默认的存储引擎,数据库系统与文件系统很大的一个不同之处在于对事务的支
         持,然而myisam存储引擎是不支持事务的,这个也不是很难理解,试想一下用户是否在所有的应用
         中都需要事务呢?在数据仓库中,如果没有ETL这些操作,只是简单的报表查询是否还需要事务的支
         持呢?此外,myisam存储引擎的另一个与众不同的地方是它的缓冲池只缓存索引文件,而不是缓冲
         数据文件,这一点和大多数的数据库都非常不同。
         myisam存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件,可以通过使用myisampack工具进一步压缩数据文件,因为myisampack工具使用赫夫曼编码静态算法来压缩数据,
         因此使用myisampack工具压缩后的表是只读的,也可以通过myisampack来解压数据文件
         在mysql5.0版本之前,myisam默认支持表大小为4GB,如果需要支持大于4GB的myisam表时,则需要指定MAX_WORS和AVG_ROW_LENGTH属性,从mysql5.0版本开始,myisam默认支持256GB的表数据,这足够满足一般的需求
    

2.sql执行流程

在这里插入图片描述
MySQL整个查询执行过程,总的来说分为5个步骤:

  1. 客户端向mysql服务器发送一条查询请求

  2. 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果,否则进行下一阶段

  3. 服务器进行sql解析、预处理、再由优化器生成对应的执行计划

  4. MySQL根据执行计划,调用存储引擎的API来执行查询

  5. 将结果返回给客户端,同时缓存查询结果

    客户端/服务端通信协议
    mysql客户端/服务端通信协议是"半双工"的,在任一时刻,要么是服务器向客户端发送数据,要么是客
    户端向服务器发送数据,这两个动作不能同时发生。一旦一端开始发送消息,另一端要接收完整个消息才能响应它,所以无法也无须将一个消息切成小块独立发送,也没有办法进行流量控制。客户端用一个单独
    的数据包将查询请求发送给服务器,所以当查询语句很长的时候,需要设置max_allowed_packet参数,如
    果查询实在是太大,服务端会拒绝接收更多数据并抛出异常。与之相反的是,服务器响应给用户的数据通
    常会很多,由多个数据包组成。但是当服务器响应客户端请求时,客户端必须完整的接收整个返回结果,
    而不能简单的只取前面几条结果,然后让服务器停止发送。因而在实际开发中,尽量保持查询简单且只返
    回必须的数据,减少通信间数据包的大小和数量是一个非常好的习惯,这也是查询中尽量避免使用select
    *以及加上LIMIT限制的原因之一

    查询缓存
    在解析一个查询语句前,如果查询缓存是打开的,那么mysql会检查这个查询语句是否命中查询缓存中的
    数据。如果当前查询恰好命中查询缓存,再检查一次用户权限后直接返回缓存中的结果。这种情况下,查
    询不会被解析,也不会生成执行计划,更不会执行。mysql将缓存存放在一个引用表(不要理解成table,可
    以认为是类似于HashMap的数据结构),通过一个哈希值索引,这个哈希值通过查询本身、当前要查询的
    数据库、客户端协议版本号等一些可能影响结果的信息计算得来。所以两个查询在任何字符上的不同(例如
    :空格、注释),都会导致缓存不会命中
    如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、mysql库中的系统表,其查询结果
    都不会被缓存。比如函数NOW()或者CURRENT_DATE()会因为不同的查询时间,返回不同的查询结果,再
    比如包含CURRENT_USER或者CONNECION_ID()的查询语句会因为不同的用户而返回不同的结果,将这样
    的查询结果缓存起来没有任何的意义

       mysql查询缓存系统会跟踪查询中涉及的每个表,如果这些表(数据或结构)发生变化,那么和这张表相关
       的所有缓存数据都将失效。正因为如此,在任何的写操作时,mysql必须将对应表的所有缓存都设置为失
       效。如果查询缓存非常大或者碎片很多,这个操作就可能带来很大的系统消耗,甚至导致系统僵死一会
       儿,而且查询缓存对系统的额外消耗也不仅仅在写操作,读操作也不例外:
    
       1.任何的查询语句在开始之前都必须经过检查,即使这条SQL语句永远不会命中缓存
       2.如果查询结果可以被缓存,那么执行完成后,会将结果存入缓存,也会带来额外的系统消耗
       基于此,并不是什么情况下查询缓存都会提高系统性能,缓存和失效都会带来额外消耗,特别是写密集型
       应用,只有当缓存带来的资源节约大于其本身消耗的资源时,才会给系统带来性能提升。可以尝试打开查
       询缓存,并在数据库设计上做一些优化:
       
       1.用多个小表代替大表,注意不要过度设计
       2.批量插入代替循环单条插入
       3.合理控制缓存空间大小,一般来说其大小设置为几十兆比较合适
       4.可以通过SQL_CACHE和SQL_NO_CACHE来控制某个查询语句是否需要进行缓存
      
       **注:SQL_NO_CACHE是禁止缓存查询结果,但并不意味着cache不作为结果返回给query,之前的缓存结果之后也可以查询到**
       
       可以在select语句中指定定查询缓存的选项,对于那些肯定要实时的从表中获取数据的查询,或者对于那些
       一天只执行一次的查询,都可以指定不进行查询缓存,使用 SQL_NO_CACHE 选项。对于那些变化不频繁的
       表,查询操作很固定,可以将该查询操作缓存起来,这样每次执行的时候不实际访问表和执行查询,只是
       从缓存获得结果,可以有效地改善查询的性能,使用 SQL_CACHE 选项
    
       查看开启缓存情况
       
       mysql> SHOW VARIABLES LIKE '%query_cache%';
    	+------------------------------+---------+
    	| Variable_name | Value |
    	+------------------------------+---------+
    	| have_query_cache | YES |
    	| query_cache_limit | 1048576 |
    	| query_cache_min_res_unit | 4096 |
    	| query_cache_size | 1048576 | # 给缓存分配的最大内存空间
    	| query_cache_type | OFF | # 是否开启查询缓存,0 表示不开启查询缓存,1
    	表示始终开启查询缓存 (不要缓 存使用 sql_no_cache), 2 表示按需开启查询缓存 (需要缓存使
    	用 sql_cache)
    	| query_cache_wlock_invalidate | OFF |
    	+------------------------------+---------+
    
        对于查询缓存的一些操作
        	FLUSH QUERY CACHE : 清理查询缓存内存碎片
    		RESET QUERY CACHE : 从查询缓存中移出所有查询
    		FLUSH TABLES : 关闭所有打开的表,同时该操作将会清空查询缓存中的内容	
    
        查询优化
    
        经过前面的步骤生成的语法树被认为是合法的了,并且由优化器将其转化成查询计划。多数情况下,一条
        查询可以有很多种执行方式,最后都返回相应的结果。优化器的作用就是找到这其中最好的执行计划。
        MySQL使用基于成本的优化器,它尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最小的
        一个。在 MySQL 可以通过查询当前会话的 last_query_cost 的值来得到其计算当前查询的成本
    
            mysql> SELECT * FROM p_product_fee WHERE total_price BETWEEN 580000 AND 680000;
            mysql> SHOW STATUS LIKE 'last_query_cost'; # 显示要做多少页的随机查询才能得到最后一查
            询结果, 这个结果是根据一些列的统计信息计算得来的,这些统计信息包括 : 每张表或者索引的
            页面个数、索引的基数、索引和数据行的长度、索引的分布情况等等
    
        有非常多的原因会导致 MySQL 选择错误的执行计划,比如统计信息不准确、不会考虑不受其控制的操作成
        本(用户自定义函数、存储过程)、MySQL认为的最优跟我们想的不一样 (我们希望执行时间尽可能短,但
        MySQL 值选择它认为成本小的,但成本小并不意味着执行时间短) 等等
        
        MySQL的查询优化器是一个非常复杂的部件,它使用了非常多的优化策略来生成一个最优的执行计划 :
        1. 重新定义表的关联顺序 (多张表关联查询时,并不一定按照 SQL 中指定的顺序进行,但有一些技巧可
        以指定关联顺序)
        2. 优化 MIN() 和 MAX()函数 (找某列的最小值,如果该列有索引,只需要查找 B+Tree索引 最左端,反之
        则可以找到最大值)
        3. 提前终止查询 (比如 : 使用 Limit 时,查找到满足数量的结果集后会立即终止查询)
        4. 优化排序 (在老版本 MySQL 会使用两次传输排序,即先读取行指针和需要排序的字段在内存中对其排
        序,然后再根据排序结果去读取数据行,而新版本采用的是单次传输排序,也就是一次读取所有的数
        据行,然后根据给定的列排序。对于I/O密集型应用,效率会高很多)
    
        查询执行引擎
        
        在完成解析和优化阶段以后,MySQL会生成对应的执行计划,查询执行引擎根据执行计划给出的指令逐步
        执行得出结果。整个执行过程的大部分操作均是通过调用存储引擎实现的接口来完成,这些接口被称为
        handler API。查询过程中的每一张表由一个 handler 实例表示。实际上,MySQL在查询优化阶段就为每一
        张表创建了一个 handler实例,优化器可以根据这些实例的接口来获取表的相关信息,包括表的所有列名、
        统计信息等。存储引擎接口提供了非常丰富的功能,但其底层仅有几十个接口,这些接口像搭积木一
        样完成了一次查询的大部分操作
    
        返回结果给客户端
    
        查询执行的最后一个阶段就是将结果返回给客户端。即使查询不到数据,MySQL 仍然会返回这个查询的相
        关信息,比如该查询影响到的行数以及执行时间等。如果查询缓存被打开且这个查询可以被缓存,MySQL
        也会将结果存放到缓存中。结果集返回客户端是一个增量且逐步返回的过程。有可能 MySQL 在生成第一条
        结果时,就开始向客户端逐步返回结果集。这样服务端就无须存储太多结果而消耗过多内存,也可以让客
        户端第一时间获得返回结果。需要注意的是,结果集中的每一行都会以一个满足客户端/服务器通信协议的
        数据包发送,再通过 TCP协议 进行传输,在传输过程中,可能对 MySQL 的数据包进行缓存然后批量发送
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值