5

从 LeetCode 的题目再看 MySQL Explain

 3 years ago
source link: http://www.justdojava.com/2021/01/16/explain/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

从 LeetCode 的题目再看 MySQL Explain

发表于 2021-01-16

| 分类于 Java

Hello 大家好,我是阿粉,作为 Java 工程师,数据库用的最多的肯定是 MySQL,而对于 MySQL 公号前面也发过很多文章,感兴趣的可以去翻翻。今天阿粉主要是想通过 LeetCode 上面的一个题目来再带大家看看 MySQL 的变量使用以及通过 Explain 的解析看看SQL 的执行过程。虽然平时在工作中对于 MySQL 使用的很多,但是相对于 MySQL 的变量使用相对还是较少的,所以阿粉在刚看到的时候还是有点懵的,不过我相信大家肯定不会像阿粉一样,毕竟能关注我们公众号的读者都是优秀的。

题目描述:编写一个 SQL 查询,查找所有至少连续出现三次的数字。并且给了一个示例,阿粉按照题目给的示例在本地创建了 Logs 表和插入相应的数据,如下:

01.png 我们可以看到在给定上面的 Logs 表中, 1 是唯一连续出现至少三次的数字,所以最后输出的结果是 1。

原始题目:LeetCode 180

刚看到题目的时候,阿粉一瞬间还是没反应过来,不知道该如何着手进行,思索了一下考虑是否可以用自连接来实现呢?然后根据题目的意思就写出了如下的 SQL。

SELECT DISTINCT
	l1.num 
FROM
	`Logs` l1,
	`Logs` l2,
	`Logs` l3 
WHERE
	l1.num = l2.num 
	AND l2.num = l3.num 
	AND l1.id = l2.id - 1 
	AND l2.id = l3.id - 1

写完过后阿粉第一次提交,提示下面错误,可以看到是最后没有将返回重命名,调整了一下 SQL,就l1.num 改成l1.num as ConsecutiveNums 再次提交,得到的第二张通过的图。

02.png

03.png

看开始看到通过,阿粉还在想这道题也没什么啊,还是 so easy 的嘛。但是突然阿粉转念一想,这个题目说的是连续出现,并没有说 ID 是连续的啊,如果 ID 不连续的话,这种就不对了,还有就是如果需要连续 4 次出现的,5 次出现的数字呢?总不能一直自连接下去吧。如果写成这样那整个 SQL 就太不灵活了。

随后阿粉就看了一下官方解答以及相关评论,果不其然虽然官方给出的解答跟阿粉的一致,但是下面的评论却有很多小伙伴都在说这个 ID 不连续的问题。

04.png

05.png

既然反馈这种做法有问题,那自然就会有好事之者会想到解决办法,果然评论区的一个大佬给出了下面的这种解法

06.png

刚看到这个解法的时候,阿粉一下子没有看懂,把这个代码进行了提交,果然也是正常的通过了。而且这种解法不会被出现几次的条件给限制。抱着学习的心态,阿粉准备研究一下这条 SQL 里面的内容。

SQL 拆解

首先这条 SQL 里面有这么几个地方让阿粉迷惑,第一个是@ 符号,然后是:= 然后还有个 case when then 语法,平日里在 CRUD 的时候没遇到过这种写法,不过不知道没关系,Google 一下就好了。网上查了下,@prev 表示的是声明变量,:=操作是 MySQL 的赋值操作,case when then when 后面接的是判断条件,条件成立则会返回then 后面的结果,需要注意的是 case 只会返回第一个符合条件的结果,剩下将会被忽略。

简单的了解了上面几个知识点过后,我们就可以对下面这条 SQL 进行拆解了。

select distinct Num as ConsecutiveNums
from (
  select Num, 
    case 
      when @currnet = Num then @count := @count + 1
      when (@currnet := Num) is not null then @count := 1
    end as CNT
  from Logs, (select @currnet := null,@count := 0) as t
) as temp
where temp.CNT >= 3
  1. 最外层的 select distinct Num as ConsecutiveNums from () as temp where temp.CNT >= 3 ; 我们可以看到中间的小括号里面被派生成了一个临时表,表名叫做 temp,并且 temp 表中有两个字段分别是Num,CNT。其实Num 则是表Logs 里面的数字,CNT 则是连续出现的累积次数,最后的where temp.CNT >= 3 则是在根据要求连续出现的次数进行查询。

  2. 派生语句SELECT Num,CASE WHEN @currnet=Num THEN @count:=@count+1 WHEN (@currnet:=Num) IS NOT NULL THEN @count:=1 END AS CNT FROM LOGS,(SELECT @currnet:=NULL,@count:=NULL) AS t 包含两个部分,一个是Select 中的case when then 另一个是from 中的 ` (select @currnet:= null,@count := null) as t 其中select @currnet:= null,@count := null 也是一个派生表,这里通过声明两个变量@currnet, @count 并赋值为null` 。

  3. 中间派生的表 temp 的内容如下,通过生成记录每个数字出现的次数的临时表来查询数据。

    07.png

下面我们通过explain 命令看下整个 SQL 的执行过程,:

08.png

  1. select_type中我们可以看到总共派生了两个表,跟我们上面分析的一致;
  2. ID 为 3 的派生表的内容是select @current := null,@count := 0 定义两个变量并赋值,并且 id 越大越先执行;
  3. case 语句中第一个when 中判断当前扫描到的 num 值与定义的变量是否一致,如果一致则 count 加一,不一致则进行下一个when 条件判断,并将count 赋值为 1 返回;
  4. 经过全表扫描过后,就得到了上面的中间表 temp 的内容;

不得不说,上面的方案是很完美的,不存在 ID 是否连续的问题,也不会多层自连接,而且也可以根据要求找出连续出现的次数,相对灵活。刚开始看到这个 SQL 的时候,阿粉并不清楚整个执行的过程,然后通过 explain 才渐渐明白整个执行过程, 而且对于在 SQL 中使用变量也有了一定的了解。

关于 explain 的详解,感兴趣的朋友可以去看公号之前发的文章MySQL 之 Explain 输出分析


Recommend

  • 44

    372 到 415 题,同级别的题目反正是越来越难。老规矩,跳过了那些付费题目。 372 35.5% Medium 373 Find K Pairs with Smallest Sums 33.3% Medium 374 Guess Number Higher...

  • 40

    从第 416 到第 460 题,跳过了需要付费的题目。付费的题目会单独放在一篇里面。 416 Partition Equal Subset Sum 40.0% Medium 417 Pacific Atlantic Water Flow 36.9% Medium 419...

  • 33

    LeetCode题目一直觉得,程序员应该持续的修炼内功,训练编程思维。最近也是不间断的在做LeetCode算法题,来锻炼思维。可是,今天在一道难度为Easy的题目上,栽了,受打击了,于是整理成此博...

  • 34

    项目介绍 本仓库总共 60 多篇原创文章,基本上都是基于 LeetCode 的题目,涵盖了所有...

  • 5

    LeetCode题目一直觉得,程序员应该持续的修炼内功,训练编程思维。最近也是不间断的在做LeetCode算法题,来锻炼思维。可是,今天在一道难度为Easy的题目上,栽了,受打击了,于是整理成此博文,来记录一下吧。 先看看题目: 12...

  • 10
    • www.raychase.net 3 years ago
    • Cache

    LeetCode 算法题目解答汇总

    LeetCode 算法题目解答汇总 [Updated on 9/22/2017] 如今回头看来,里面很多做法都不是最佳的,有的从复杂度...

  • 5

    LeetCode 题目分类与面试问题整理 Awsome-Github 资源列表 分享计算机视觉、机器学习、深度学习各个研究领域的GitHub资源列表,包括数据集、论文、代码、牛人主页等...

  • 4

    精选 100 道力扣(LeetCode)上最热门的题目,本篇文章只有 easy 级别的,适合初识算法与数据结构的新手和想要在短时间内高效提升的人。1.两数之和https://leetcode-cn.com/probl...

  • 7
    • www.guofei.site 2 years ago
    • Cache

    【LeetCode】matrix相关题目

    59. Spiral Matrix II 复用 Spiral Matrix I 那个题 先用一个矩阵填入连续数字 然后展开它,以此确定展开顺序,并记下来

  • 2
    • www.guofei.site 2 years ago
    • Cache

    【LeetCode】LinkedList相关题目

    【LeetCode】LinkedList相关题目 2022年03月05日    Author:Guofei 文章归类: 0x81_数据结构与算法    文章编号: 593

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK