上面的查询过程符合语义,但是如果在filter条件能过滤很多数据的时候,先进行数据的过滤,在进行内联接会获取更好的性能,比如我们手工写一下:
- mysql> SELECT
- -> no, name , score
- -> FROM student stu JOIN ( SELECT s_no, score FROM score s WHERE s.score >80) as sc ON no = s_no;
- +------+-------+-------+
- | no | name | score |
- +------+-------+-------+
- | S001 | Sunny | 98 |
- | S003 | Kevin | 88 |
- +------+-------+-------+
- 2 rows in set (0.00 sec)
上面写法语义和第一种写法语义一致,得到相同的查询结果,上面查询过程是:
- mysql> SELECT s_no, score FROM score s WHERE s.score >80;
- +------+-------+
- | s_no | score |
- +------+-------+
- | S001 | 98 |
- | S003 | 88 |
- +------+-------+
- 2 rows in set (0.00 sec)
第二步:执行内连接
- -> ON no = s_no;
- +------+-------+-------+
- | no | name | score |
- +------+-------+-------+
- | S001 | Sunny | 98 |
- | S003 | Kevin | 88 |
- +------+-------+-------+
- 2 rows in set (0.00 sec)
如上两种写法在语义上一致,但查询性能在数量很大的情况下会有很大差距。上面为了和大家演示相同的查询语义,可以有不同的查询方式,不同的执行计划。实际上数据库本身的优化器会自动进行查询优化,在内联接中ON的联接条件和WHERE的过滤条件具有相同的优先级,,具体的执行顺序可以由数据库的优化器根据性能消耗决定。也就是说物理执行计划可以先执行过滤条件进行查询优化,如果细心的读者可能发现,在第二个写法中,子查询我们不但有行的过滤,也进行了列的裁剪(去除了对查询结果没有用的c_no列),这两个变化实际上对应了数据库中两个优化规则:
- filter push down
- project push down
如上优化规则以filter push down 为例,示意优化器对执行plan的优化变动:

3. LEFT OUTER JOIN
左外联接语义是返回左表所有行,右表不存在补NULL,为了演示作用,我们查询没有参加考试的所有学生的成绩单:
- mysql> SELECT
- -> no, name , s.c_no, s.score
- -> FROM student stu LEFT JOIN score s ON sstu.no = s.s_no
- -> WHERE s.score is NULL;
- +------+------+------+-------+
- | no | name | c_no | score |
- +------+------+------+-------+
- | S002 | Tom | NULL | NULL |
- +------+------+------+-------+
- 1 row in set (0.00 sec)
上面查询的执行逻辑上也是分成两步:
- mysql> SELECT
- -> no, name , s.c_no, s.score
- -> FROM student stu LEFT JOIN score s ON sstu.no = s.s_no;
- +------+-------+------+-------+
- | no | name | c_no | score |
- +------+-------+------+-------+
- | S001 | Sunny | C01 | 80 |
- | S001 | Sunny | C02 | 98 |
- | S001 | Sunny | C03 | 76 |
- | S002 | Tom | NULL | NULL | -- 右表不存在的补NULL
- | S003 | Kevin | C01 | 78 |
- | S003 | Kevin | C02 | 88 |
- | S003 | Kevin | C03 | 68 |
- +------+-------+------+-------+
- 7 rows in set (0.00 sec)
第二步:过滤查询
- mysql> SELECT
- -> no, name , s.c_no, s.score
- -> FROM student stu LEFT JOIN score s ON sstu.no = s.s_no
- -> WHERE s.score is NULL;
- +------+------+------+-------+
- | no | name | c_no | score |
- +------+------+------+-------+
- | S002 | Tom | NULL | NULL |
- +------+------+------+-------+
- 1 row in set (0.00 sec)
(编辑:威海站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|