查询的原理

在一个查询中常包含下述子句:

1、select,2、distinct,3、join,4、on,5、from,6、where,7、having,8、group by,9、order by,10、limit

在查询执行过程中,每个子句按照一定的顺序被执行,每个子句被执行时都会产生一张虚拟表,只有最后一步生成的虚拟表才会返回给用户。

我们用实际的例子来讲解下查询的执行过程,先准备以下两张表:

create table t_student(

id bigint(20) not null auto_increment comment '主键ID',

name varchar(10) not null default '' comment '姓名',

age tinyint(3) not null default 0 comment '年龄',

primary key (id)

)engine=innodb default charset=utf8 comment '学生信息表';

create table t_grade(

id bigint(20) not null auto_increment comment '主键ID',

student_id bigint(20) not null default 0 comment '学生ID',

level varchar(4) comment '水平:Null.未评级、A.优秀、B.中等、C.不及格',

primary key (id)

)engine=innodb default charset=utf8 comment '成绩表';

并插入一些基本数据:

insert into t_student(name,age) value('小A',16),('小B',17),('小C',18),('小D',17),('小E',18);

insert into t_grade(student_id,level) value(1,'A'),(2,'B'),(3,'C'),(4,'B'),(5,'Null');

现有一个查询需求“查出是哪些水平拥有至少2个以上且年龄大于等于17岁的学生,并按人数由少到多排序”,那么根据这个需求我们可以写出如下代码:

select g.level, count(g.student_id) as total_student from t_student s left join t_grade g on s.id=g.student_id

where s.age>=17 group by g.level having count(g.student_id) >= 2 order by total_student asc;

下面我们就来说说上述SQL的执行顺序,

1)在一个查询语句中,from子句总是最先执行的,form操作会得到关联表的笛卡尔积,如下图

2)on子句会进行筛选操作,只有符合on后条件的行才会被筛选出来,我们刚刚所写查询的on后条件是s.id=g.student_id,那么不满足这个条件的行就会被去除,如下图有红色小三角标记的是会被保留的行

3)join子句如果是left join或right join,那么保留表(由于我们在SQL中使用的是left join,因此这里的保留表指的是t_student)中未匹配的行(因on子句被去掉的行)会作为外部行添加到虚拟表中,如下图

从上图对于join子句的表现不够直观,我们再向t_student表中插入一条数据,且这条数据是没有与t_grade表有关联关系的,insert into t_student(name,age) value('小F',16);

再看如下截图,由于刚插入的那条数据没有与t_grade表有关联关系,原本是要被on子句被去掉的,但是由于使用了left join,会保留左表的所有数据,同时右表没有与之关联的列值被赋值为Null,这就是添加外部行(left join的全写是left outer join,这里的outer就是指外部行)。

4)接着where子句会对得到的行再进行过滤,只有满足where后条件的行才会被筛选出来,见下图

这里补充讲解一点,对于left join或right join,在on过滤完之后会添加保留表中被on过滤掉的行,而被where过滤的行则是永久性过滤。

5)group by对经过了where条件筛选后的数据进行分组;

6)having需要和group by配合使用,因为having使用的前提是group by已经对数据完成了分组,而having就是来对分组后的数据再进行筛选,如下图

需要注意的是,若在left join或right join查询中,在select子句后使用count(1)或count(*),可能会把添加的外部行统计入内,从而导致查询结果与预期结果不符,对于这样的查询最好是使用count(具体列名)。

7)select将需要返回的列筛选出来,我们可以看到select的优先级并不高;

8)如果查询语句中带有去重子句distinct,则会执行去掉重复记录的操作;

去掉重复记录的原理是对进行distinct操作的列增加一个唯一索引。若SQL中使用了group by,则distinct是无效的,因为已经进行了分组,不会移除任何行。

9)接下来是order by,在我们得到了预期的数据后,可以对数据进行排序,以方便阅读,由于我们所执行的SQL查询出来只有一条数据,所以这里的排序效果并不明显,如下图

需要注意的是若不使用order by则查询出来的数据是无序的,并非是按照主键有序排列,这是因为关系型数据库是基于数学来实现的,关系对应数学中的集合,表中的数据对应集合中的元素,而集合本身是无序的,因此在不使用order by的情况下结果并不一定按照主键顺序进行排列,故我们在需要有序输出行记录时必须使用order by。

还有在对列进行排序时,若列没有索引,则排序会造成一定的性能开销。一般通过show status like ‘%sort%’ \G; 来观察相关变量,以此来判断是否可以通过添加索引来降低开销。

还需说明的是null值在升序中会首先被选出,因为在order by子句中null值被视为最小值。

10)最后是limit,拿到从指定位置开始的指定行数据,limit常和order by一起使用,其使用方式是limit n,m,表示拿到从第n行开始(不包含n行,实际从n+1行开始,如要取到的数据包含第n行,则应该是n-1)的共m行数据。

需要注意的是在大数据量下使用limit来分页效率是比较低的,因为需要在这么多数据量下去定位位置(定位n)。

这里详细对多表联查的过程做下说明,假设我们联查表A、B、C、D

先是表A、B做笛卡尔积,即两表记录数相乘,然后通过on来筛掉不符合的记录,如果是left join或right join这种方式的联查,则还需要保留外部行,怎么理解保留外部行,就是保留表中被过滤条件过滤掉的数据,这样就得到了表A、B的联查数据,接下来再将得到的数据和表C做笛卡尔积,并重复这一过程,直到最后一张表完成这一过程,最后就得到了A、B、C、D四表联查的数据;

额外知识点

在where子句后书写过滤条件时,有两种过滤情况是不允许发生的。

①数据没有分组前或者说在group by没有执行前,在where子句中不能使用分组函数,例如max()、min()、count()、sum()等,正因为这个限制的存在就能理解having子句存在的意义了,因为我们还存在对分组后的数据进行统计的需要;

错误的SQL:

select id from t_commodity c where count(commodity_type_id)>=5;

MySQL提示:

②为select子句后的列取别名,并在where子句里直接使用列别名,是不被允许的。因为where的执行顺序是要高于select的,因为在列还没有被选取的情况下,就开始使用列别名明显是不行的。

错误的SQL:

select `name` as n from t_commodity where n='精进';

MySQL提示:

MySQL学习分享-->查询-->查询的原理的更多相关文章

  1. MySQL学习分享--Thread pool实现

    基于<MySQL学习分享--Thread pool>对Thread pool架构设计的详细了解,本文主要对Thread pool的实现进行分析,并根据Mariadb和Percona提供的开 ...

  2. MySQL学习分享-->查询-->查询的分类

    MySQL的查询可以分为交叉联接.内联接.外联接.自然联接.straight_join 下面对于查询的学习,会用到以下四张表: create table t_commodity_type( `id` ...

  3. MySql学习(三) —— 子查询(where、from、exists) 及 连接查询(left join、right join、inner join、union join)

    注:该MySql系列博客仅为个人学习笔记. 同样的,使用goods表来练习子查询,表结构如下: 所有数据(cat_id与category.cat_id关联): 类别表: mingoods(连接查询时作 ...

  4. 【SQL】MySQL学习笔记1-----子查询

    1.什么叫子查询? 通俗的讲就是查询中有查询,SQL语句中有多个select语句. 2.什么地方可以嵌入子查询? SELECT 列 (不在标准之内) FROM 表 (可以嵌入,作为表存在) WHERE ...

  5. Entity Framework with MySQL 学习笔记一(查询)

    参考 : http://msdn.microsoft.com/en-us/data/jj574232.aspx EF 查询基本上有3中 默认是 Lazy Loading 特色是只有在需要数据的时候EF ...

  6. MySQL学习笔记(二)—查询

    一.多表连接查询 新建两张表t_user.t_order.              1.内连接      返回满足条件的所有记录. (1)显式内连接      使用inner join关键字,在on ...

  7. MySQL学习笔记(3) - 查询服务器版本,当前时间,当前用户

    SELECT VERSION(); --显示当前服务器版本 SELECT NOW(); --显示当前日期时间 SELECT USER(); --显示当前用户 MySQL中语句规范: 1.关键字和函数名 ...

  8. MySQL学习(二)索引原理及其背后的数据结构

    首先区分几个概念: 聚集索引 主索引和辅助索引(即二级索引) innodb中每个表都有一个聚簇索引(clustered index ),除此之外的表上的每个非聚簇索引都是二级索引,又叫辅助索引(sec ...

  9. MySQL学习分享--数值类型

    数值类型 MySQL的数值类型包括整数类型.浮点数类型.定点数类型.位类型. 整数类型 MySQL支持的整数类型有tinyint.smallint.mediumint.int.bigint(范围从小到 ...

随机推荐

  1. jQuery wrap wrapAll wrapInner使用

    jQuery wrap wrapAll wrapInner使用 <%@ page language="java" import="java.util.*" ...

  2. Canvas get/putImageData

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Docker,容器,虚拟机和红烧肉

    Docker火了,有多火你自己看看下面的统计数据就知道了 在发布4个月的时间里,下载量就超过50000次,github上收到超过4000个star,涌现了超过100个贡献者,并且有超过150个项目和超 ...

  4. 这个发现是否会是RSA算法的BUG、或者可能存在的破解方式?

    笔者从事各种数据加解密算法相关的工作若干年,今天要说的是基于大数分解难题的RSA算法,可能有些啰嗦. 事情的起因是这样的,我最近针对一款芯片进行RSA CRT解密的性能优化.因为期望值是1024bit ...

  5. C# 6 与 .NET Core 1.0 高级编程 - C# 6 改进

    个人原创译文,转载请注明出处.有不对的地方欢迎指出与交流. 英文原文:Professional C# 6 and .NET Core 1.0 - What's New in C# 6 C# 6 改进 ...

  6. 使用express.js框架一步步实现基本应用以及构建可扩展的web应用

    最近过年在家有点懈怠,但是自己也不断在学习新的前端技术,在家琢磨了express.js的web框架. 框架的作用就是提高开发效率,快速产出结果.即使不使用框架,我们也会在开发过程中逐渐形成构成框架. ...

  7. 制作jar文件

    一.制作可运行jar文件 使用java的swing.awt制作了一个简单的界面交互模块.程序打成jar包后,能双击运行,制作过程: 1.eclipse →properties →Export,选择ja ...

  8. 文件下载类型__response

    response.setContentType(MIME)的作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据. 例如web浏览器就是通过MI ...

  9. C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)),不对的地方欢迎指出与交流. 章节出自<Professional C ...

  10. githup教程

    http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/瘳雪峰-Git教程http://w ...