我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MYSQL 中 exists 语句执行效率变低

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MYSQL 中 exists 语句执行效率变低

        在ORACLE 中,我们常常推荐使用exists 来替代in,往往也能取得比较好的优化效果。在ORACLE应用迁往MYSQL的过程中,我们发现部分in 的子查询语句带到MYSQL中,其执行效率变得非常低下,这很让人觉得匪夷所思。于是,我分析了一波。

    对两个表,分别是一大一小进行关联查询:

mysql> select count(*) from users;
+----------+
| count(*) |
+----------+
|       19 |
+----------+
1 row in set
mysql> select count(*) from orders;
+----------+
| count(*) |
+----------+
|    86310 |
+----------+
1 row in set
mysql>

开启profile,发现无论是子查询是大表还是小表 ,exists的语句总是比in执行慢:

mysql> show profiles;
+----------+------------+--------------------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                                      |
+----------+------------+--------------------------------------------------------------------------------------------+
|        1 | 1.08661625 | select count(1) from orders o where o.user_id in(select u.id from users u)                 |
|        2 | 1.56956275 | select count(1) from orders o where exists (select 1 from users u where u.id = o.user_id)  |
|        3 | 0.81266425 | select count(1) from users u where u.id in(select o.user_id from orders o)                 |
|        4 |  8.4164905 | select count(1) from users u where exists (select 1 from  orders o where u.id = o.user_id) |
+----------+------------+--------------------------------------------------------------------------------------------+
4 rows in set

而查看exists语句的profile内容,发现其存在多个executing 和sending data过程,这是整个sql执行的主要耗时过程:

mysql> show profile for query 2
;
+----------------------------+----------+
| Status                     | Duration |
+----------------------------+----------+
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.5E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 1E-6     |
| Sending data               | 1.3E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.7E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.1E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 1E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.1E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.2E-5   |
| executing                  | 2E-6     |
| Sending data               | 1.5E-5   |
| end                        | 3E-6     |
| query end                  | 3E-6     |
| waiting for handler commit | 1E-5     |
| closing tables             | 9E-6     |
| freeing items              | 0.000152 |
| cleaning up                | 1.7E-5   |
+----------------------------+----------+
100 rows in set

而在in 子查询中,sending data这个过程只有一次,这也是整个sql执行主要耗时地方:

mysql> show profile for query 1;
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 9.3E-5   |
| Executing hook on transaction  | 6E-6     |
| starting                       | 8E-6     |
| checking permissions           | 5E-6     |
| checking permissions           | 4E-6     |
| Opening tables                 | 0.004849 |
| init                           | 1.8E-5   |
| System lock                    | 1.4E-5   |
| optimizing                     | 1.4E-5   |
| statistics                     | 3.1E-5   |
| preparing                      | 2.2E-5   |
| executing                      | 3E-6     |
| Sending data                   | 1.081273 | 《《《《《《《《《《《《《《《《《《《
| end                            | 1.3E-5   |
| query end                      | 3E-6     |
| waiting for handler commit     | 1E-5     |
| closing tables                 | 5.2E-5   |
| freeing items                  | 0.000171 |
| cleaning up                    | 2.9E-5   |
+--------------------------------+----------+

关于sending data和executing 解析:

Sending data

The thread is reading and processing rows for a SELECT statement, and sending data to the client. Because operations occurring during this state tend to perform large amounts of disk access (reads), it is often the longest-running state over the lifetime of a given query.

 说Sending data 是:线程正在为一个select语句读取和处理行,并且发送数据到客户端。因为这期间操作倾向于大量的磁盘访问(读取),所以这常是整个查询周期中运行时间最长的阶段。(这是MySQL 5.5的解释,5.7的解释完全一样,但是5.7多了一个Sending to client状态)

这样就清楚了,Sending data 做了 读取,处理(过滤,排序等。。)和发送 三件事情,接下来再看该状态下的cpu 和 io 信息 以分析语句的瓶颈是 读取还是处理 ,再做相应的优化调整。。

executing

The thread has begun executing a statement.

在exists语句中不断地executing和Sending data 应该是在不断地扫描抓取数据进行匹配,那这应该与MYSQL 的算法有关,通过trace查看其实是在多次子查询 join_execution:

  {
            "subselect_execution": {
              "select#": 2,
              "steps": [
                {
                  "join_execution": {
                    "select#": 2,
                    "steps": [
                    ] 
                  } 
                }
              ] 
            } 
          },

想知道这是鸡肋吗,不知有没有相关的解析?

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MYSQL 中 exists 语句执行效率变低

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

mysql怎么查找效率低的SQL语句

本篇内容主要讲解“mysql怎么查找效率低的SQL语句”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mysql怎么查找效率低的SQL语句”吧!MySQL通过慢查询日志定位那些执行效率较低的SQL
2023-06-01

mybatis中update语句执行无效怎么解决

这篇文章主要讲解了“mybatis中update语句执行无效怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatis中update语句执行无效怎么解决”吧!项目里mybatis有
2023-06-21

MySql中sql语句执行过程是什么

今天小编给大家分享一下MySql中sql语句执行过程是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。sql语句的执行过程
2023-07-05

MySQL中一条update语句是怎么执行的

本篇内容主要讲解“MySQL中一条update语句是怎么执行的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL中一条update语句是怎么执行的”吧!前期准备⭐⭐首先创建一张表,然后插入
2023-06-29

MySql中sql语句执行过程详细讲解

目录前言:sql语句的执行过程:查询缓存:分析器:优化器:执行器:总结前言:很多人都在使用mysql数据库,但是很少有人能够说出来整个sql语句的执行过程是怎样的,如果不了解执行过程的话,就很难进行sql语句的优化处理,也很难设计出来优良
2023-02-21

编程热搜

目录