mysql(1)—— 详解一条sql语句的执行过程

  SQL是一套标准,全称结构化查询语言,是用来完成和数据库之间的通讯的编程语言,SQL语言是脚本语言,直接运行在数据库上。同时,SQL语句与数据在数据库上的存储方式无关,只是不一样的数据库对于同一条SQL语句的底层实现不一样罢了,但结果相同。这有点相似于java中接口的做用,一个接口能够有不一样的实现类,不一样的实现类对于接口中方法的实现方式能够不一样,结果能够相同。这里SQL语言的做用就相似于java中的接口,数据库就相似于java中接口的实现类,SQL语句就相似于java接口中的方法。不一样的是java中接口的不一样实现类对于接口中方法的执行结果能够相同,也能够不一样,而不一样的数据库对于同一条SQL语句的执行是相同的。(这里只是作一个类比,方便咱们理解java

  通常状况下,大部分SQL语句在不一样的数据库上是通用的,但咱们知道每一个数据库都有本身独有的特性,像在MySql数据库中,可使用substr(取字符串),trim(去空格),ifnull(空值处理函数),还可使用limit语句对数据库表进行截取,但这些都是oracle数据库没有的。(类比接口实现类中,实现类独有的方法,而接口中没有的mysql

  这里简单介绍一下mysql数据库,mysql数据库是一款关系型数据库,所谓关系型数据库就是以二维表的形式存储数据,使用行和列方便咱们对数据的增删改查。程序员

  这篇博客,咱们以mysql数据库为例,对一条sql语句的执行流程进行分析。(本篇博客不涉及到表链接)sql

  首先,建立一张student表,字段有自增主键id,学生姓名name,学科subject,成绩grade数据库

  建表语句:编程

DROP TABLE IF EXISTS student;
CREATE TABLE `student` (
  `id` int(5) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `subject` varchar(10) DEFAULT NULL,
  `grade` double(4,1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8;

  初始化数据:oracle

INSERT INTO student(`name`,`subject`,grade)VALUES('aom','语文',88);
INSERT INTO student(`name`,`subject`,grade)VALUES('aom','数学',99);
INSERT INTO student(`name`,`subject`,grade)VALUES('aom','外语',55);

INSERT INTO student(`name`,`subject`,grade)VALUES('jack','语文',67);
INSERT INTO student(`name`,`subject`,grade)VALUES('jack','数学',44);
INSERT INTO student(`name`,`subject`,grade)VALUES('jack','外语',55);

INSERT INTO student(`name`,`subject`,grade)VALUES('susan','语文',56);
INSERT INTO student(`name`,`subject`,grade)VALUES('susan','数学',35);
INSERT INTO student(`name`,`subject`,grade)VALUES('susan','外语',77);

INSERT INTO student(`name`,`subject`,grade)VALUES('alice','语文',88);
INSERT INTO student(`name`,`subject`,grade)VALUES('alice','数学',77);
INSERT INTO student(`name`,`subject`,grade)VALUES('alice','外语',100);

INSERT INTO student(`name`,`subject`,grade)VALUES('rajo','语文',33);
INSERT INTO student(`name`,`subject`,grade)VALUES('rajo','数学',55);
INSERT INTO student(`name`,`subject`,grade)VALUES('rajo','外语',55);

下面咱们来看一下,数据在数据库中的存储形式。编程语言

  (图1.0)函数

如今针对这张student表中的数据提出一个问题:要求查询出挂科数目多于两门(包含两门)的前两名学生的姓名,若是挂科数目相同按学生姓名升序排列。spa

下面是这条查询的sql语句

SELECT `name`,COUNT(`name`) AS num FROM student WHERE grade < 60 GROUP BY `name` HAVING num >= 2 ORDER BY num DESC,`name` ASC LIMIT 0,2;

执行结果:

  图(1.1)

以上这条sql语句基本上归纳了单表查询中全部要注意的点,那么咱们就以这条sql为例来分析一下一条语句的执行流程。

1,一条查询的sql语句先执行的是 FROM student 负责把数据库的表文件加载到内存中去,如图1.0中所示。(mysql数据库在计算机上也是一个进程,cpu会给该进程分配一块内存空间,在计算机‘服务’中能够看到,该进程的状态)

  图(1.2)

2,WHERE grade < 60,会把(图1.0)所示表中的数据进行过滤,取出符合条件的记录行,生成一张临时表,以下图所示。

  图(1.3)

 

3,GROUP BY `name`会把图(1.3)的临时表切分红若干临时表,咱们用下图来表示内存中这个切分的过程。

               

  图(1.4)              图(1.5)               图(1.6)              图(1.7)

4,SELECT 的执行读取规则分为sql语句中有无GROUP BY两种状况。

  (1)当没有GROUP BY时,SELECT 会根据后面的字段名称对内存中的一张临时表整列读取。

  (2)当查询sql中有GROUP BY时,会对内存中的若干临时表分别执行SELECT,并且只取各临时表中的第一条记录,而后再造成新的临时表。这就决定了查询sql使用GROUP BY的场景下,SELECT后面跟的通常是参与分组的字段和聚合函数,不然查询出的数据要是状况而定。另外聚合函数中的字段能够是表中的任意字段,须要注意的是聚合函数会自动忽略空值。

  咱们仍是以本例中的查询sql来分析,如今内存中有四张被GROUP BY `name`切分红的临时表,咱们分别取名为 tempTable1,tempTable2,tempTable3,tempTable4分别对应图(1.4)、图(1.5)、图(1.6),图(1.7)下面写四条"伪SQL"来讲明这个查询过程。

SELECT `name`,COUNT(`name`) AS num FROM tempTable1;
SELECT `name`,COUNT(`name`) AS num FROM tempTable2;
SELECT `name`,COUNT(`name`) AS num FROM tempTable3;
SELECT `name`,COUNT(`name`) AS num FROM tempTable4;

最后再次成新的临时表,以下图:

  图(1.8)

5,HAVING num >= 2对上图所示临时表中的数据再次过滤,与WHERE语句不一样的是HAVING 用在GROUP BY以后,WHERE是对FROM student从数据库表文件加载到内存中的原生数据过滤,而HAVING 是对SELECT 语句执行以后的临时表中的数据过滤,因此说column AS otherName ,otherName这样的字段在WHERE后不能使用,但在HAVING 后可使用。但HAVING的后使用的字段只能是SELECT 后的字段,SELECT后没有的字段HAVING以后不能使用。HAVING num >= 2语句执行以后生成一张临时表,以下:

   图(1.9)

6,ORDER BY num DESC,`name` ASC对以上的临时表按照numname进行排序。

7,LIMIT 0,2取排序后的前两个。

以上就是一条sql的执行过程,同时咱们在书写查询sql的时候应当遵照如下顺序。

SELECT XXX FROM XXX WHERE XXX GROUP BY XXX HAVING XXX ORDER BY XXX LIMIT XXX;

 

  最后说一点,咱们做为程序员,研究问题仍是要仔细深刻一点的。当你对原理了解的有够透彻,开发起来也就驾轻就熟了,不少开发中的问题和疑惑也就迎刃而解了,并且在面对其余问题的时候也可作到举一反三。固然在开发中没有太多的时间让你去研究原理,开发中要以实现功能为前提,可等项目上线的后,你有大把的时间或者空余的时间,你大可去刨根问底,深刻的去研究一项技术,为以为这对一名程序员的成长是很重要的事情。

相关文章
相关标签/搜索