查询的原理

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

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. SVN官方版本下载地址

    TortoiseSVN 客户端 &  Language packs 语言包 : https://tortoisesvn.net/downloads.html VisualSVN 插件官方地址: ...

  2. window.open a.href打开窗口referer的问题

    window.open a.href打开窗口referer的问题: JSP: <%@ page language="java" import="java.util. ...

  3. jq操作radio,设置选中、获取选中值

    <label><inputtype="radio"name="sex"value="1">男</label&g ...

  4. HttpSesstionActivationLIstener示例

    HttpSesstionActivationLIstener示例: http://www.cnblogs.com/xdp-gacl/p/3969249.html 钝化的session会已session ...

  5. 将 Callout 容器添加到移动设备应用程序中

    在移动设备应用程序中,callout 是在应用程序顶部弹出的容器.该容器可以容纳一个或多个组件,并且支持不同类型的布局. callout 容器可以是模态或非模态容器.模态容器在其关闭之前接受所有的键盘 ...

  6. JDBC 的编程步骤

    1.加载数据库驱动 2.获得数据库连接 3.创建语句 4.执行查询 5.遍历结果集 6.关闭数据库连接 尽量把数据库的连接步骤写成一个单独的java类,使用的时候直接new一个对象, import j ...

  7. mac下sublime 配置查看源码

    sublime及package control的安装查看之前一篇文章:http://www.cnblogs.com/xdwa/p/5805101.html 安装ctags 安装完毕package co ...

  8. setTimeout小总结

    ▓▓▓▓▓▓ 大致介绍 今天看了一篇文章,觉得写得不错,所以学习了一下,这篇博客是我自己的理解和总结 原文:你应该知道的 setTimeout 秘密 主要内容: 1.setTimeout原理 2.se ...

  9. angular2使用官网npm install下载依赖失败的处理方法

    上一两个月在学习angular2,在下载依赖阶段看官网是直接自动下载的,[npm install] 就能把依赖全部弄下来.不过作为新手的我,是倒腾来倒腾去都倒不出来,因为老是报同一个错.官网也还有手动 ...

  10. php curl详细解析和常见大坑

    1. 拿来先试试手 比如我们以著名的"测试网络是否连接"的网站--百度为例,来尝试下curl <?php // create curl resource $ch = curl ...