• MySql(随记)


    一条MySql执行过程

    首先Mysql的架构分为两层,Server层和存储引擎层。
    Server层:MySql大多数核心功能,主要包括,连接器,查询缓存,解释器,预处理器,优化器,执行器等
    存储引擎层:负责数据的获取和存储。(innodb,MyISAM)

    连接器

    1.首先经过TCP三次握手,随后进行权限验证,若有问题则返回“Access denied for user”。若无问题则权限验证成功,后续该用户在此连接里的任何操作,都会基于连接开始时读到的权限进行权限逻辑的判断。所以,如果一个用户已经建立了连接,即使管理员中途修改了该用户的权限,也不会影响已经存在连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置
    2.show processlist:查看连接命令
    3.其中Command 命令行为Sleep则代表为空闲连接,空闲连接的最大空闲时长,由 wait_timeout 参数控制的,默认值是 8 小时(28880秒)
    4.MySQL 服务支持的最大连接数由 max_connections 参数控制
    5.有短链接(执行一次SQL就建立并断开一次连接),长连接(在连接期间执行多条SQL)
    长连接占内存的问题如何解决?
    1.定期断开长连接 2.客户端主动重置连接(这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。)

    查询缓存

    这个查询缓存是以 key-value 形式保存在内存中的,key 为 SQL 查询语句,value 为 SQL 语句查询的结果。查询语句到来时,先查询缓存,若命中则返回,若未命中则继续查询。
    为什么查询缓存用处不大?
    只要一个表有更新操作,那么这个表的查询缓存就会被清空。而更新操作是比较频繁的

    解析SQL

    1.词法分析。MySQL 会根据你输入的字符串识别出关键字出来,如关键字SELECT,UPDATE,FROM等
    2.语法分析。根据词法分析的结果,语法解析器会根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法,如果没问题就会构建出 SQL 语法树,这样方便后面模块获取 SQL 类型、表名、字段名、 where 条件等等。

    执行SQL

    执行SQL主要有三个阶段:
    prepare 阶段,也就是预处理阶段;
    optimize 阶段,也就是优化阶段;
    execute 阶段,也就是执行阶段;

    1.预处理器

    主要做两件事1.检查查询语句中的表和字段是否存在。2. 将 select * 中的 * 符号,扩展为表上的所有列;

    2.优化器

    优化器主要负责将 SQL 查询语句的执行方案确定下来,比如在表里面有多个索引的时候,优化器会基于查询成本的考虑,来决定选择使用哪个索引。

    3.执行器

    MySQL 就真正开始执行语句了,这个工作是由「执行器」完成的。在执行的过程中,执行器就会和存储引擎交互了,交互是以记录为单位的。
    主要三种方式执行过程,执行器和存储引擎的交互过程如下:
    主键索引查询:
    执行器第一次查询,会调用 read_first_record 函数指针指向的函数,因为优化器选择的访问类型为 const,这个函数指针被指向为 InnoDB 引擎索引查询的接口,把条件 id = 1 交给存储引擎,让存储引擎定位符合条件的第一条记录。
    存储引擎通过主键索引的 B+ 树结构定位到 id = 1的第一条记录,如果记录是不存在的,就会向执行器上报记录找不到的错误,然后查询结束。如果记录是存在的,就会将记录返回给执行器;
    执行器从存储引擎读到记录后,接着判断记录是否符合查询条件,如果符合则发送给客户端,如果不符合则跳过该记录。
    执行器查询的过程是一个 while 循环,所以还会再查一次,但是这次因为不是第一次查询了,所以会调用 read_record 函数指针指向的函数,因为优化器选择的访问类型为 const,这个函数指针被指向为一个永远返回 - 1 的函数,所以当调用该函数的时候,执行器就退出循环,也就是结束查询了。
    全表扫描:
    执行器第一次查询,会调用 read_first_record 函数指针指向的函数,因为优化器选择的访问类型为 all,这个函数指针被指向为 InnoDB 引擎全扫描的接口,让存储引擎读取表中的第一条记录
    执行器会判断读到的这条记录的 name 是不是 iphone,如果不是则跳过;如果是则将记录发给客户的(是的没错,Server 层每从存储引擎读到一条记录就会发送给客户端,之所以客户端显示的时候是直接显示所有记录的,是因为客户端是等查询语句查询完成后,才会显示出所有的记录)。
    执行器查询的过程是一个 while 循环,所以还会再查一次,会调用 read_record 函数指针指向的函数,因为优化器选择的访问类型为 all,read_record 函数指针指向的还是 InnoDB 引擎全扫描的接口,所以接着向存储引擎层要求继续读刚才那条记录的下一条记录,存储引擎把下一条记录取出后就将其返回给执行器(Server层),执行器继续判断条件,不符合查询条件即跳过该记录,否则发送到客户端;
    一直重复上述过程,直到存储引擎把表中的所有记录读完,然后向执行器(Server层) 返回了读取完毕的信息;
    执行器收到存储引擎报告的查询完毕的信息,退出循环,停止查询。
    索引下推:
    索引下推能够减少二级索引在查询时的回表操作,提高查询的效率,因为它将 Server 层部分负责的事情,交给存储引擎层去处理了。
    不使用索引下推(MySQL 5.6 之前的版本)时,执行器与存储引擎的执行流程是这样的:
    Server 层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,也就是定位到 age > 20 的第一条记录;
    存储引擎根据二级索引的 B+ 树快速定位到这条记录后,获取主键值,然后进行回表操作,将完整的记录返回给 Server 层;
    Server 层在判断该记录的 reward 是否等于 100000,如果成立则将其发送给客户端;否则跳过该记录;
    接着,继续向存储引擎索要下一条记录,存储引擎在二级索引定位到记录后,获取主键值,然后回表操作,将完整的记录返回给 Server 层;
    如此往复,直到存储引擎把表中的所有记录读完。、
    没有索引下推的时候,每查询到一条二级索引记录,都要进行回表操作,然后将记录返回给 Server,接着 Server 再判断该记录的 reward 是否等于 100000。
    使用索引下推后,判断记录的 reward 是否等于 100000 的工作交给了存储引擎层,过程如下 :
    Server 层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,也就是定位到 age > 20 的第一条记录;
    存储引擎定位到二级索引后,先不执行回表操作,而是先判断一下该索引中包含的列(reward列)的条件(reward 是否等于 100000)是否成立。如果条件不成立,则直接跳过该二级索引。如果成立,则执行回表操作,将完成记录返回给 Server 层。
    Server 层在判断其他的查询条件(本次查询没有其他条件)是否成立,如果成立则将其发送给客户端;否则跳过该记录,然后向存储引擎索要下一条记录。
    如此往复,直到存储引擎把表中的所有记录读完。
    可以看到,使用了索引下推后,虽然 reward 列无法使用到联合索引,但是因为它包含在联合索引(age,reward)里,所以直接在存储引擎过滤出满足 reward = 100000 的记录后,才去执行回表操作获取整个记录。相比于没有使用索引下推,节省了很多回表操作。

  • 相关阅读:
    linux开发之制作Ubuntu根文件系统
    海带软件分享——日常办公学习软件分享(收藏)
    ZooKeeper数据模型/znode节点深入
    【ROS进阶篇】第一讲 常用API介绍
    蓝桥杯 大小写转换
    机器学习-SVM算法
    Apache SCXML2 RCE漏洞
    秦简总经理王建忠:论都江堰泛计算操作系统的商业价值
    谷粒商城 高级篇 (四) --------- Elasticsearch-Rest-Client
    Redis 如何实现库存扣减操作和防止被超卖?(荣耀典藏版)
  • 原文地址:https://blog.csdn.net/weixin_43527478/article/details/132941355