详细拆解 SQL 查询语句的执行顺序是怎样的 目录一. 引言二. SQL查询语句举例三. SQL查询语句顺序执行误区四. 查询语句步骤分析五. SQL查询语句执行顺序总结六. 面试小问题6.1 WHERE 和 HAVING 谁的过滤范围更广6.2 为什么 WHERE 之后不能使用聚合函数进行过滤6.3 为什么 WHERE 的执行效率要比 HAVING 高6.4 SQL的执行顺序为什么要这样设计呢一. 引言我们都知道掌握 MySQL 数据库几乎是我们程序员必备的一项技能对于简单的数据库操作而言我们通常做的就是CRUD无非再加上一些筛选过滤条件在 MySQL 数据库中我们会用到很多的关键字那么它们的执行顺序是怎么样的呢二. SQL查询语句举例下面我写一个比较复杂的SQL查询语句几乎包含了所有的查询关键字以及聚合函数我们来分析一下它的执行顺序。SELECT(查询想要获取的字段数据还可以DISTINCT 去重)FROM(从哪些表中查写表名并可以为其起别名)(LEFT / RIGHT 可有可无) JOIN(继续跟表名也可以起别名)ON(多表连接的条件第一次过滤)WHERE(不包含聚合函数的过滤条件BETWEEN...AND... IN可以用在WHERE中第二次过滤)GROUP BY(分组关键字例如通过部门分组)HAVING(包含聚合函数的过滤条件如MAX()MIN()AVG()等聚合函数第三次过滤)ORDER BY ASC/DESC(排序关键字升序或者降序)LIMITXY(分页关键字X表示从第几条开始Y表示一页显示多少条)三. SQL查询语句顺序执行误区也许有很多人在一开始认为SQL的查询语句都是从上往下执行的但其实是错的SQL查询语句的执行顺序并不是按顺序执行的。MySql在查找数据时会根据一个合适的执行顺序去执行我们的查询语句从而提高查找数据的效率和操作数据的效率这也与我们以后要接触的SQL语句的优化有一定的关联性。四. 查询语句步骤分析OK经过上面的层层铺垫我们开始进入正题现在我们一步步分析上面的一大长串SQL查询语句的执行顺序我会尽可能说的详细一些下面我们就以两张表的查询为例三张表四张表类比推理即可1第一步执行 FROM。既然是查询它就会先去执行 FROM因为它要知道你要去查询那些表的数据所以首先会去 FROM如果只有一张表底层不会做什么事如果你有两张以上的表底层其实会去对这些表中的每一个元素做一个笛卡尔积其实这个过程中是有一个虚拟表的这张表的数据量非常大只是我们不知道2第二步执行 ON。在进行完表数据的笛卡尔积之后紧接着会去执行两张表的连接条件 ON通过ON的过滤条件会筛选出来有用的数据将大量无用数据全部剔除然后筛选出来的数据又形成了一个新的虚拟表这张新的虚拟表数据量已经比较小了3第三步执行 (RIGHT/LEFT) JOIN。如果我们对两张表进行了左外或者右外连接在完成第二步筛选之后就会根据你写的左外LEFT JOIN或者右外 RIGHT JOIN再去补充一些 ON 连接查询条件中没有查询到的数据然后对补充后的数据又形成一个新的虚拟表如果没有左右外连接那么它就会直接连接合并数据形成虚拟表4第四步执行WHERE。我们就会去执行 WHERE 中的过滤条件比如我们IN关键字BETWEEN...AND...关键字再次将满足我们条件的数据过滤出来将无用的数据再次剔除又形成一张数据量更小虚拟的表5第五步执行GROUP BY。我们就会对剩下的少量数据进行分组执行 GROUP BY分组命令6第六步执行 HAVING。完成分组之后我们还会对数据进行进一步过滤比如说我们想得到平均工资最高或者最低的部门相关数据将通过 HAVING 关键字即可过滤得到此时经过了层层过滤底层的那张虚拟表的数据已经非常非常小了7第七步执行 SELECT 。经过前面六部层层过滤之后我们得到了一个满足了我们所有条件的一个虚拟表这个时候我们才会去做 SELECT 操作因为我们不一定要想要所有数据可能只要其中的几个字段此时会再进行 SELECT 操作将我们想要得字段和相关数据筛选出来。8第八步执行 DISTINCT。经过 SELECT 查询之后我们可能还会对一些重复出现的字段进行去重此时就会执行 DISTINCT。9第九步执行ORDER BY (ASC/DESC) 。DISTINCT 过滤玩字段之后可以说现在得到的数据就是我们想要的全部数据了但此时表中的数据还处于一个无序的状态此时我们可能还想对得到的数据在做一个排序比如升序排列降序排列等等。10第十步执行 LIMIT (XY) 。经过排序之后我们现在得到的就是已经排好序的而且是含有所有有效数据的一张虚拟表这个时候我们还会做最后的一步操作分页所以说分也页是最后进行的。五. SQL查询语句执行顺序总结通过上面我们一大堆的分析我们可以得出以下结论在SQL查询语句中各个关键字以及过滤条件的执行顺序如下FROM --- ON --- (LEFT/RIGHT) JOIN --- WHERE (BETWEEN...AND.../IN) --- GROUP BY --- HAVING --- SELECT --- DISTINCT --- ORDER BY (ASC/DESC) --- LIMIT如下图所示六. 面试小问题下面是扩展小问题这些问题面试的过程中很有可能会问到的哦希望各位同学认真看完能真正的理解它们。6.1 WHERE 和 HAVING 谁的过滤范围更广这个问题其实不难我们知道HAVING 可以使用聚合函数进行条件过滤而 WHERE 却不行因此在过滤范围方面HAVING 的过滤范围要比 WHERE 的更广泛。6.2 为什么 WHERE 之后不能使用聚合函数进行过滤首先一点我们要知道想要使用分组函数首先你得先分好组。通过上面我们的分析可以知道分组操作是在 WHERE 操作执行完之后才会去执行的那么自然而然这个问题不就迎刃而解了吗在进行 WHERE 操作的时候我们还没有对数据进行分组操作当然也无法使用分组函数了啊。6.3 为什么 WHERE 的执行效率要比 HAVING 高想要弄明白这个问题还需要彻底理解SQL查询语句的执行顺序我来简单举个例子各位应该就会明白了。比如说现在我有一张员工部门表有一万条数据并对部门进行分组分组之后我还要查员工年龄大于35岁并且平均工资最高的那个部门的信息。1先使用 WHERE 再使用 HAVING大家想一下如果先我们使用了 WHERE 过滤条件假设 WHERE 过滤条件是大于35岁吧那都是老员工了条件也比较苛刻经过我们 WHERE 之后一万条数据只剩下了 500 条数据这个时候我们再去对这 500 条数据去分组再去求最大值要做的事情会很少性能就可以提升一大截。2不使用 WHERE只使用 HAVING如果我不使用 WHERE 条件去过滤我们将年龄的过滤条件为了省事也写到 HAVING 后面去过滤这个时候就会有一个问题因为 HAVING 是在分组操作执行之后才去做的那么我们就会把这一万条数据全部进行分组哐哐一顿分过组之后发现我们只要年龄大于 35 岁的那么我们前面对另外那 9500 条数据做的全部都是无用功因为我们根本不需要这样是不是会非常耗费系统的性能这样来说明相信大家对 WHERE 基于会有一个全新的认识了。6.4 SQL的执行顺序为什么要这样设计呢不知道你们有没有发现我在讲述 SQL 查询语句执行顺序的时候多次强调底层有一张虚拟表并强调这张虚拟表的数据越来越小。各位想数据越少我们对数据进行操作时耗费的时间也越少性能是不是越高啊我们多表查询时的第一次过滤 ON 过滤掉了大量的无用的笛卡尔积数据第二次条件过滤 WHERE 过滤掉了大量不满足条件的无用数据第三次条件过滤 HAVING 更多是为了使用聚合函数又过滤掉了少量的无用数据这三次过滤都是在底层虚拟表上进行行数据的过滤各位能听懂吧就是对这个虚拟表的每一行数据进行过滤过滤完成之后我们又进行的 SELECT 过滤对我们需要的列数据又进行了一次过滤取出我们想要的列数据经过 SELECT 之后我们又采用 DISTINCT 再次对重复的行数据进行过滤经过层层严苛的筛选过滤底层的那张虚拟表数据其实已经非常少了各位可能会觉得很麻烦这里我再次强调数据量小的时候对数据进行操作的速度是非常非常快的因此SQL查询语句的执行顺序都是有逻辑可循的各位同学可以再仔细揣摩揣摩多思考几遍。总而言之言而总之就一句话。SQL 查询语句执行顺序之所以这样设计最终目的都是为了提高数据的查询效率与操作效率避免做无用功。