草庐IT

你清楚 SQL 的执行顺序吗?

ixdba 2023-03-28 原文

目标读者

  • 开发人员
  • 学生
  • DBA
  • 其他工作中涉及数据库的相关人员

一. 概述

1.1. 测试环境概览

  • 操作系统:CentOS 7.9 x86_64
  • 数据库:MySQL 5.7.38
  • Docker 版本:1.13.1-209

为了快速部署测试环境,数据库运行于 Docker 内。

1.2. 测试环境初始化

启动 Docker 服务

yum install -y docker

systemctl start docker
# 禁止开机自启动
systemctl disable docker

启动 MySQL 服务(Docker 内)

mypwd='tiger'      # mysql 密码
myport=33016       # mysql 端口
myversion='5.7.38' # mysql 版本号

docker run -itd \
  --name test-mysql \
  -e MYSQL_ROOT_PASSWORD="${mypwd}" \
  -p ${myport}:3306 \
  -d mysql:${myversion}

docker ps | grep -w mysql
# 2c5c103d94e4        mysql:5.7.38        "docker-entrypoint..."   35 seconds ago      Up 34 seconds       33060/tcp, 0.0.0.0:33016->3306/tcp   test-mysql

验证 MySQL 服务启动成功

yum install -y mysql

[root@c7009 ~]# mysql -uroot -ptiger -h 127.0.0.1 --port 33016
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.38 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> select 'hello mysql';
+-------------+
| hello mysql |
+-------------+
| hello mysql |
+-------------+
1 row in set (0.00 sec)

至此,MySQL 测试环境初始化完成。

1.3. 为什么要了解 SQL 的执行顺序?

有如下 SQL:

select @rn := @rn + 1 as row_num,
       ht.name
from mysql.help_topic ht,
     (select @rn := 0) as rn
order by row_num;
image.png

如果你不能理解以上输出背后的逻辑,请继续往下看吧。

二. SQL 执行顺序

2.1. 优先级

我们都知道,算术表达式中加减乘除是有优先级的,而一条 SQL 的各部分也是有执行先后顺序的:

(8)select                  (9)distinct <select_list>
(1)from <left_table>       (3)<join_type> join <right_table>
(2)on <join_condition>
(4)where <where_condition>
(5)group by <group_by_list>
(6)with {CUBE|ROLLUP}
(7)having <having_condtion>
(10)order by <order_by_list>
(11)limit <limit_number>

2.2. 验证

回看 1.3 节 SQL,拆分后形成以下几部分:

-- part 1
select @rn := @rn + 1 as row_num,
       ht.name

-- part 2
from mysql.help_topic ht,
     (select @rn := 0) as rn

-- part 3
order by row_num;

套用 2.1 节优先级列表,此 SQL 各部分执行顺序如下:

  • Step 1: part 2 - 写法相当于 ht cross join rn,先对 @rn 会话变量进行了赋值操作。
  • Step 2: part 1 - 每行对 @rn 进行递增操作(所谓行间计算)。
  • Step 3: part 3 - 对结果集进行排序。

总结

日常工作中,我们可能会遇到一些复杂 SQL,如果对 SQL 自身的执行顺序不了解,很难真正熟悉 SQL 所对应的业务逻辑。

授人与渔

如果你还想提升自身的 SQL 水平,以下书籍是比较推荐

  • SQL Cookbook
  • Oracle SQL 高级编程
  • SQL Server 2005 技术内幕 T-SQL 查询

关于我

经历:DBA 一枚,09 年开始接触数据库,一直专注于此领域。

此系列文章初衷:多年学习/工作经验,有些沉淀,也想分享些东西出来,算对这个行业的一点点微薄贡献,希望 IT 这个圈子能越来越好。

其他说明:不能保证全文没有任何不妥之处,如有发现,不吝赐教。

有关你清楚 SQL 的执行顺序吗?的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  3. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  4. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  5. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  6. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  7. Hive SQL 五大经典面试题 - 2

    目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类

  8. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  9. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  10. ruby-on-rails - Rake 任务仅调用一次时执行两次 - 2

    我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里

随机推荐