mysql整体结构大致分三层:
- 客户端
- 核心服务
- 存储引擎
MySQL客户端:用来处理 连接处理,授权认证,安全等功能
核心服务层:用来查询解析,分析,优化,缓存,内置函数(如时间、数学、加密等函数)所有的跨存储引擎的功能也在这一层实现:存储过程、触发器、视图。
存储引擎:负责mysql中的数据存储和提取,每种存储引擎都有其优势和劣势。核心服务层通过API与存储引擎通信,这些API接口屏蔽不同存储引擎间的差异。
mysql server逻辑架构:
详细结构可分为:
连接池组件
管理服务和工具组件
sql接口组件
查询分析器组件
优化器组件
缓冲组件
插件事存储引擎
物理文件
存储引擎是基于表的 不是基于数据库。
理解:mysql分为MySQL server层和存储引擎层,在server层中又分为连接层和sql层
连接层:客户端或应用程序通过接口连接sql,最先连接处理的就是连接层,
连接层包括通信协议,线程处理,用户名密码认证三个部分,
通信协议负责检测客户端版本是否与服务端兼容,线程处理是指每个连接请求都会分配一个对应对立的线程,用户密码认证创建的账号和密码,以及host主机授权是都可以连接到 mysql服务器。
sql层
sql层包含权限判断,查询缓存,解析器,预处理,查询优化器,缓存和执行计划
1> 权限判断可以通过审核用户有没有访问某个库,某个表,或者表里某行的权限。
2> 查询缓存通过query cache进行操作,如果数据在query cache中,则直接返回结果给客户端。
3> 查询解析器针对sql语句进行解析,判断语法是否正确,并生成解析器。
4> 预处理器解决解析器无法解析的语义。
5> 优化器对sql语句进行改写和相应的优化,例如对连接表重排序,对外连接转内连接,代数等价法则,计算和减少常量表达式,自查询优化,早期终结,相等传递等,并生成最优的执行计划,然后就饿可以调用程序的API接口,通过存储引擎层访问数据。
存储引擎层:
Innodb存储引擎:支持事务
Innodb存储引擎将数据放在一个逻辑表空间中,这个表空间就行黑盒一样由Innodb存储引擎自身进 行管理,从mysql4.1版本开始,他可以将每个Innodb存储引擎的表单独存放到一个独立的ibd文件 中,此外,Innodb存储引擎支持用裸设备来建立其表空间。 Innodb存储引擎通过使用多版本并发控制(MVCC)来获得高并发性,并且实现了sql标准的4中隔离级 别,默认为RR级别,同时,使用一种被称为next-key locking的策略来避免幻读现象的产生,除此 之外,Innodb存储引擎还提供了插入缓存,二次写入,自适应hash索引,预读等高性能和高可用的 功能。对于表中的数据存储,Innodb存储引擎采用聚集的方式,因此每张表的存储都是按主键的顺 序进行存放,如果没有显示在表定义时指定主键,Innodb存储引擎会为每一行生成一个6字节的 ROWID,并以此作为主键。
myisam存储引擎:不支持事务,支持全文索引,但不用。Myisam存储引擎的另一个与众不同的地方是它的缓冲池只缓存索引文件,而不是缓冲 数据文件。Myisam存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件。
MySQL 整个查询执行过程,总的来说分为 5 个步骤 :
- 客户端向 MySQL 服务器发送一条查询请求
- 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果,否则进入下一阶段
- 服务器进行 SQL解析、预处理、再由优化器生成对应的执行计划
- MySQL 根据执行计划,调用存储引擎的 API来执行查询
- 将结果返回给客户端,同时缓存查询结果
针对查询缓存的理解:
在解析一个查询语句前,如果查询缓存是打开的,那么 MySQL 会检查这个查询语句是否命中查询缓存中的 数据。如果当前查询恰好命中查询缓存,在检查一次用户权限后直接返回缓存中的结果。这种情况下,查 询不会被解析,也不会生成执行计划,更不会执行。MySQL将缓存存放在一个引用表 (不要理解成table,可 以认为是类似于 HashMap 的数据结构),通过一个哈希值索引,这个哈希值通过查询本身、当前要查询的 数据库、客户端协议版本号等一些可能影响结果的信息计算得来。所以两个查询在任何字符上的不同 (例如 : 空格、注释),都会导致缓存不会命中。如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL库中的系统表,其查询结果 都不会被缓存。比如函数 NOW() 或者 CURRENT_DATE() 会因为不同的查询时间,返回不同的查询结果,再 比如包含 CURRENT_USER 或者 CONNECION_ID() 的查询语句会因为不同的用户而返回不同的结果,将这样 的查询结果缓存起来没有任何的意义
MySQL 查询缓存系统会跟踪查询中涉及的每个表,如果这些表 (数据或结构) 发生变化,那么和这张表相关 的所有缓存数据都将失效。正因为如此,在任何的写操作时,MySQL必须将对应表的所有缓存都设置为失 效。如果查询缓存非常大或者碎片很多,这个操作就可能带来很大的系统消耗,甚至导致系统僵死一会 儿,而且查询缓存对系统的额外消耗也不仅仅在写操作,读操作也不例外 :
- 任何的查询语句在开始之前都必须经过检查,即使这条 SQL语句 永远不会命中缓存
- 如果查询结果可以被缓存,那么执行完成后,会将结果存入缓存,也会带来额外的系统消耗
基于此,并不是什么情况下查询缓存都会提高系统性能,缓存和失效都会带来额外消耗,特别是写密集型 应用,只有当缓存带来的资源节约大于其本身消耗的资源时,才会给系统带来性能提升。可以尝试打开查 询缓存,并在数据库设计上做一些优化 :
- 用多个小表代替一个大表,注意不要过度设计
- 批量插入代替循环单条插入
- 合理控制缓存空间大小,一般来说其大小设置为几十兆比较合适
- 可以通过 SQL_CACHE 和 SQL_NO_CACHE 来控制某个查询语句是否需要进行缓存
注 : SQL_NO_CACHE 是禁止缓存查询结果,但并不意味着 是 cache 不作为结果返回给 不 query,之前的 , 缓存结果之后也可以查询到
可以在 SELECT 语句中指定查询缓存的选项,对于那些肯定要实时的从表中获取数据的查询,或者对于那些 一天只执行一次的查询,都可以指定不进行查询缓存,使用 SQL_NO_CACHE 选项。对于那些变化不频繁的 表,查询操作很固定,可以将该查询操作缓存起来,这样每次执行的时候不实际访问表和执行查询,只是 从缓存获得结果,可以有效地改善查询的性能,使用 SQL_CACHE 选项