SQL语句在MySQL数据库中普遍经历的过程如下:
- 客户端发起查询请求到MySQL数据库服务器监听端口;
- MySQL数据库server端接收到请求;
- server端从已有的连接池或者新建一个线程,用来处理客户端发起的请求;
- server层对请求进行身份认证和权限认证;
- SQL解析器对SQL语句进行词法分析、语法分析以及生成语法树;
- 优化器对SQL进行优化,选择最佳执行计划;
- 存储引擎层执行SQL后,将查询到的SQL语句返回;
- 客户端最终接收到返回的结果集。
上面只是一条SQL语句普遍经历的过程,select、delete、update、insert语句在MySQL数据库中的执行过程又有什么区别呢?如果SQL带有过滤条件、分组语句、排序语句、join语句,那SQL的执行过程又有何不同呢?
一、select语句在MySQL数据库中经历的过程
上面的步骤1、2、3不同类型sql都是一样的过程,细微处可能略有差异,比如说用户是通过MySQL客户端发起的请求,通过应用中配置的jdbc发起的请求等,不同实例server端的监听端口也可能不同,客户端可以通过不同机制获取到连接线程,比如说druid连接池等。server端接受到请求后会验证发起请求的客户端是否通过身份认证、是否具有对查询对象的权限,都通过后才会正式开始执行sql。
从第5步开始,我们假设一条select语句主体内容如下:
select age,name from users where age > 20 group by age order by age limit 50;
SQL解析器首先对提取处select语句中的语法关键词,select、from、where、group by、order by、limit等,然后对语法进行分析,比如说符号是否正确、查询的列是否存在、表是否存在,接着生成语法分析树。
优化器可能对SQL进行改写,如in转换为exists,或者or转换为union等,接着优化器基于统计信息选择成本最小的执行计划,比如说是走索引或者是全表扫描。如果是从大量数据中查询少量数据,可能就是走索引,优化器会预估不同执行计划的成本。
select优化后最终到存储引擎层开始执行,假设这里存储引擎用的是innodb,innodb会首先到内存中去寻找要查找行记录所在的数据页,通过innodb中的一个哈希表快速判断对应的数据页id是否存在,如果不存在,则会通过B+树索引,最终定位到需要查找的数据的地址,然后将数据页加载到内存中,再通过二分查找法找到对应的行记录。
存储引擎根据过滤条件,过滤出要查找的记录,如果使用了limit 50语句,则只会过滤出50行数据返回到server层。
server层根据order by和group by语句,对结果集进行排序和分组。如果结果集比较大,内存中放不下,则会使用临时表来存放分组结果和排序结果,结果集最终返回到客户端。