SQL案例分析之部分查询和全部查询

大家好,我是知数堂SQL 优化班老师 网名:骑龟的兔子

今天给大家看一个案例来讨论,一个重要的SQL优化思路,部分查询和全部查询。

下面是要使用的两个表 

root@mysql3306.sock>[employees]>select * from departments ;
+---------+--------------------+
| dept_no | dept_name          |
+---------+--------------------+
| d009    | Customer Service   |
| d005    | Development        |
| d002    | Finance            |
| d003    | Human Resources    |
| d001    | Marketing          |
| d004    | Production         |
| d006    | Quality Management |
| d008    | Research           |
| d007    | Sales              |
+---------+--------------------+


root@mysql3306.sock>[employees]>desc dept_emp2 ;
+-----------+---------+------+-----+---------+-------+
| Field     | Type    | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| emp_no    | int     | NO   | PRI | NULL    |       |
| dept_no   | char(4) | NO   | PRI | NULL    |       |
| from_date | date    | NO   |     | NULL    |       |
| to_date   | date    | NO   |     | NULL    |       |
+-----------+---------+------+-----+---------+-------+

现在需求是求出 每个部门的员工号从小到大的五个员工。

我们按照思路写下如下SQL

desc with w1 as (
select d.* 
,row_number() over(PARTITION by d.dept_no order by emp_no asc ) rn 
from dept_emp d 
)
select dept_no ,group_concat(emp_no  order by emp_no asc SEPARATOR '|' ) c 
 from w1 
 where rn <=5 
 group by dept_no\G


*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 331143
     filtered: 33.33
        Extra: Using where; Using filesort
*************************** 2. row ***************************
           id: 2
  select_type: DERIVED
        table: d
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 331143
     filtered: 100.00
        Extra: Using filesort
2 rows in set, 2 warnings (0.00 sec)




oot@mysql3306.sock>[employees]>with w1 as (
    -> select d.*
    -> ,row_number() over(PARTITION by d.dept_no order by emp_no asc ) rn
    -> from dept_emp2 d
    -> )
    -> select dept_no ,group_concat(emp_no  order by emp_no asc SEPARATOR '|' ) c
    ->  from w1
    ->  where rn <=5
    ->  group by dept_no;
+---------+-------------------------------+
| dept_no | c                             |
+---------+-------------------------------+
| d001    | 10017|10055|10058|10108|10140 |
| d002    | 10042|10050|10059|10080|10132 |
| d003    | 10005|10013|10036|10039|10054 |
| d004    | 10003|10004|10010|10018|10020 |
| d005    | 10001|10006|10008|10012|10014 |
| d006    | 10009|10010|10029|10033|10067 |
| d007    | 10002|10016|10034|10041|10050 |
| d008    | 10007|10015|10019|10040|10046 |
| d009    | 10011|10038|10049|10060|10088 |
+---------+-------------------------------+
9 rows in set (0.60 sec)

从上面的执行计划中,可以看出rows 331143 这就是说,对这个表的这么多

数据进行了排序和操作,这就是全部查询

那看下,下面的SQL

root@mysql3306.sock>[employees]>desc with w1 as (
    -> select
    -> d.* from departments d1 join lateral
    -> (
    -> select d.*
    -> from dept_emp2 d
    -> where d.dept_no = d1.dept_no
    ->  order by  d.dept_no ,d.emp_no
    -> limit 5
    -> ) d on  d.dept_no = d1.dept_no
    -> )
    -> select dept_no ,group_concat(emp_no  order by emp_no asc SEPARATOR '|' ) c
    ->  from w1
    ->  group by dept_no;
 *************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: d1
   partitions: NULL
         type: index
possible_keys: PRIMARY
          key: dept_name
      key_len: 162
          ref: NULL
         rows: 9
     filtered: 100.00
        Extra: Using index; Using temporary; Using filesort; Rematerialize (<derived3>)
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived3>
   partitions: NULL
         type: ref
possible_keys: <auto_key0>
          key: <auto_key0>
      key_len: 16
          ref: employees.d1.dept_no
         rows: 2
     filtered: 100.00
        Extra: NULL
*************************** 3. row ***************************
           id: 3
  select_type: DEPENDENT DERIVED
        table: d
   partitions: NULL
         type: ref
possible_keys: ix_dept_emp
          key: ix_dept_emp
      key_len: 16
          ref: employees.d1.dept_no
         rows: 41376
     filtered: 100.00
        Extra: NULL
3 rows in set, 2 warnings (0.00 sec)


root@mysql3306.sock>[employees]>with w1 as (
    -> select
    -> d.* from departments d1 join lateral
    -> (
    -> select d.*
    -> from dept_emp2 d
    -> where d.dept_no = d1.dept_no
    ->  order by  d.dept_no ,d.emp_no
    -> limit 5
    -> ) d on  d.dept_no = d1.dept_no
    -> )
    -> select dept_no ,group_concat(emp_no  order by emp_no asc SEPARATOR '|' ) c
    ->  from w1
    ->  group by dept_no;
+---------+-------------------------------+
| dept_no | c                             |
+---------+-------------------------------+
| d001    | 10017|10055|10058|10108|10140 |
| d002    | 10042|10050|10059|10080|10132 |
| d003    | 10005|10013|10036|10039|10054 |
| d004    | 10003|10004|10010|10018|10020 |
| d005    | 10001|10006|10008|10012|10014 |
| d006    | 10009|10010|10029|10033|10067 |
| d007    | 10002|10016|10034|10041|10050 |
| d008    | 10007|10015|10019|10040|10046 |
| d009    | 10011|10038|10049|10060|10088 |
+---------+-------------------------------+
9 rows in set (0.23 sec)

上面的SQL是每个dept_no 只要选出5个之后就不进行查询了,从执行计划中能够可以看出,良好的索引和排序策略,也直接把排序也消除了。这就是部分查询,即只查询满足要求的数量进而达到优化的目的。

 从上面同一种需求的,两种不同SQL写法,可以看出不同的思路,就有可能导致不同的效率。

我是知数堂SQL 优化班老师~ ^^

最新一期SQL优化课,在12月份开始。

如有关于SQL优化方面疑问和一起交流的请加 并且 @兔子@知数堂SQL优化

高性能MySQL,SQL优化群 有叶金荣,吴炳锡 两位大神坐镇 :579036588

欢迎加入 知数堂大家庭。

我的微信公众号:SQL开发与优化(sqlturning)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值