【6】mysql查询性能优化-关联子查询

【README】

0. 先说结论:一般用inner join来改写in和exist,用left join来改写not in,not exist;(本文会比较内连接,包含in子句的子查询,exist的性能 )

1. 本文总结自高性能mysql 6.5.1章节【关联子查询】

2. 数据库表及数据特征:

  • wn_film_tbl: 电影表, 50w数据量;
  • wn_actor_tbl: 演员表, 50w数据量;
  • wn_file_actor_rel_tbl: 电影演员关联表, 10w数据量;

3. ddl如下:

CREATE TABLE `wn_film_tbl` (`film_id` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '电影id',`film_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '电影名称',`release_year` int(11) NOT NULL COMMENT '上映年份',`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`last_modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`film_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='电影表'CREATE TABLE `wn_actor_tbl` (`actor_id` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '演员id',`actor_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '演员名称',`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`last_modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='演员表'CREATE TABLE `wn_film_actor_rel_tbl` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`film_id` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '电影id',`actor_id` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '演员id',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`last_modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`),KEY `idx_film_id` (`film_id`) COMMENT '电影id索引',KEY `idx_actor_id` (`actor_id`) COMMENT '演员id索引'
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='电影与演员关联表'

【1】查询某演员参演的电影清单

1. 具体的,查询 演员0420AAAID000099参演的电影清单,通过造数,该演员参演的电影有 15000部;

2. 几种不同的实现方式:

  • 方案1: 使用 包含in()子句的子查询(性能非常低,作为反例,供各位看官参考)
  • 方案2:使用内连接;
  • 方案3:使用exists;

【1.1】使用包含in()子句的子查询

1. sql如下(为了方便打印执行计划,这里仅查询一条#limit 1):

select sql_no_cache * 
from wn_film_tbl film
where film_id in (select film_id from wn_film_actor_rel_tbl  where actor_id='0420AAAID000099')
limit 1
;

2. 查看其执行计划及查询成本:

  • explain 查看执行计划;
  • show status like 'last_query_cost' 查询上一个sql的执行成本;(成本的最小单位是随机读取1个大小为4K的数据页 )

3. 执行计划剖析(执行计划列的含义,参见
mysql_explain执行计划字段解析-CSDN博客):

4. 关联表执行步骤:

  • 第1步: 扫描film_actor_rel_tbl 表的普通索引 idx_actor_id ,查询 actor_id 等于0420AAAID000099 的 电影演员关联记录,得到列表 result_list
  • 第2步:全表扫描查询结果result_list(猜测是在内存中,因为extra没有 using temporary);
  • 第3步:扫描film表的主键索引树,查询film表中film_id(主键) 等于 result_list#film_id 字段值的记录并返回;

5. 对于上述步骤的总结:mysql对任何关联都执行嵌套循环关联操作(即先查询 rel表,然后全表扫描rel表,循环遍历rel表,再在单次遍历中循环遍历 film表 );

  • 有个问题: 为什么不反着来? 先查询 film表,再在循环遍历film过程中,遍历rel表(动脑筋的时候到了);
  • 小表驱动大表原则;  为什么小表驱动大表,大表驱动小表不行吗?(如果理解了上面的问题,就可以推导出小表驱动大表的依据)

6. 嵌套循环关联查询步骤如下:

  • 查询外层表的数据行, 并构建外层表的迭代器;
  • 遍历外层表迭代器,获取单个外层表数据行(第1层循环)
    • 根据单个外层表数据行,查询内层表的数据行,并构建内层表迭代器;
    • 遍历内层表迭代器,获取单个内层表数据行(第2层循环)
      • 合并外层与内层表数据行,构建输出结果;
      • 内层表迭代器滑动;
  • 外层表迭代器滑动;


 【1.2】使用内连接

sql如下:

select sql_no_cache film.* 
from wn_film_tbl film
inner join wn_film_actor_rel_tbl rel on film.film_id = rel.film_id 
where rel.actor_id='0420AAAID000099'
limit 1

【敲黑板】

  • 显然,根据执行计划,我们看到,mysql先查询了rel 表,然后再查询了 film表,为什么?(id相同,则按照从上到下的顺序执行)
  • 为什么不是先查询film表,再查询rel表;

【1.3】使用exists

sql如下:

select sql_no_cache film.* 
from wn_film_tbl film
where exists (select * from wn_film_actor_rel_tbl rel where rel.actor_id='0420AAAID000099'and rel.film_id = film.film_id 
) 
limit 1;


【2】总结:

1. 根据 last_query_cost 可以看到: 内连接需要扫描 36572个数据页;in子句的子查询需要扫描42467个数据页,所以内连接性能  【优于】 in子句的子查询

2. 从扫描行数来看: 内连接性能优于 in子句的子查询, in子句的子查询 优于  exists

问题:为什么 exits子查询的 last_query_cost结果显示为0呢?没懂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/1110.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 面向对象——1.基本概念

本章学习链接如下: 基本概念与语法 类(Class):定义了一组对象共有的属性和方法的蓝图。类是创建对象的模板。 对象(Object):类的实例。对象包含实际的数据和操作数据的方法。 属性&#xff0…

NLP_知识图谱_三元组实战

文章目录 三元组含义如何构建知识图谱模型的整体结构基于transformers框架的三元组抽取baselinehow to use预训练模型下载地址训练数据下载地址 结构图代码及数据bertconfig.jsonvocab.txt datadev.jsonschemas.jsontrain.jsonvocab.json 与bert跟data同个目录model.pytrain.py…

原型和原型链--图解

https://juejin.cn/post/7255605810453217335 prototype是函数的属性(一个对象),不是对象的属性,普通函数和构造函数的prototype属性是空对象{}(其实有2个属性,一个是constructor&a…

Vue3: toRefs与toRef的基本使用

一、前言 本文主要介绍toRefs与toRef的基本使用。 二、内容 1、基本概念 作用: toRefs与toRef可以将一个响应式对象中的每一 个属性,转换为ref对象;不同 toRefs与toRef功能一致,但toRefs可以批量转换。 2、toRefs 如果把reactive定义的…

记录交叉编译环境配置--海思开发板的 嵌入式nginx和 php的移植

嵌入式 lnmp搭建的记录 一些交叉编译的配置环境思路分享:P:php编译PHP可能遇到的问题configure阶段:Makefile-make阶段:Makefile-make install阶段: N:Nginx 文章比较水,并没有没解决什么实际问…

java面向对象的继承Shape

* - Shape基类 拥有draw()和erase()两个方法 * - 基于Shape类创建Circle子类 * - 基于Shape类创建Square子类 * - 创建Shape类创建Triangle子类 * - 创建随机形状发生的类(不是子类) * - 定义公共类(测试类),创建Shape类的数组对象长度为10,并为对象数组赋值其内容C…

二维码门楼牌管理应用平台建设:助力场所整改与消防安全

文章目录 前言一、二维码门楼牌管理应用平台的构建背景二、二维码门楼牌管理应用平台在场所整改中的作用三、二维码门楼牌管理应用平台的意义与价值四、二维码门楼牌管理应用平台的未来展望 前言 随着城市管理的日益精细化,二维码门楼牌管理应用平台的建设成为了提…

el-table 遇到的问题一

点击按钮一,出现table1 点击按钮二,出现table2 刚开始很简单,就用简单的 v-if 添加,但是会出现问题,就是点击按钮一,会出现table1,点击按钮二,会出现table2,再点击按钮…

C++ - STL详解(七)— stack和queue的介绍及使用

目录 一. stack 1.1 stack的介绍 1.2 stack的定义 1.3 stack的使用 ​编辑 二. queue 2.1 queue的介绍 2.2 queue的定义 2.3 queue的使用 一. stack 1.1 stack的介绍 stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除…

Java中的消息队列(如RabbitMQ、Kafka)是如何工作的

Java中的消息队列(Message Queue)是一种用于应用程序之间或应用程序组件之间进行异步通信的机制。消息队列允许发送者(生产者)将消息发送到队列中,而接收者(消费者)可以从队列中读取并处理这些消…

代码随想录算法训练营第十八天 | 513.找树左下角的值、112. 路径总和、113. 路径总和ii

代码随想录算法训练营第十八天 | 513.找树左下角的值、112. 路径总和、113. 路径总和ii 自己看到题目的第一想法看完代码随想录之后的想法自己实现过程中遇到哪些困难 链接: 513.找树左下角的值 链接: 112. 路径总和,和 113. 路径总和ii 链接: 从中序与后序遍历序…

Debezium系列之:部署Debezium采集Oracle数据库的详细步骤

Debezium系列之:部署Debezium采集Oracle数据库的详细步骤 一、部署Debezium Oracle连接器二、Debezium Oracle 连接器配置三、添加连接器配置四、可插拔数据库与不可插拔数据库一、部署Debezium Oracle连接器 部署的详细步骤可以参考博主这篇技术文章: Debezium系列之:安装…

怎么用3ds MAX制作蜂窝状模型?

1、新建多边形:打开3ds MAX软件,在样条线中新建一个多边形。 2、设置参数:切换到顶视图,设置多边形的参数,例如半径为10,变数为6,以形成一个六边形的基础。 3、复制并形成圆柱状:打开…

如何通过Postgres的日志进行故障排查?

文章目录 一、配置日志记录二、查看和分析日志三、使用日志进行故障排查的示例四、总结 在进行数据库管理和维护时,日志分析是一项至关重要的技能。PostgreSQL的日志记录功能可以帮助我们追踪数据库的运行状态,定位问题,以及优化性能。下面&a…

深入Git配置

git配置 git config -h usage: git config [<options>]Config file location--global use global config file--system use system config file--local use repository config file--worktree use per-worktree con…

【Java】如何获取客户端IP地址

在项目中往往涉及到“获取客户端IP地址”&#xff0c;常见到下面这样子的代码&#xff1a; package com.utils;import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.http.server.reactive.ServerHttpRequest; import java.net…

逻辑运算符

一 介绍 用于连接多个条件&#xff08; 多个关系表达式&#xff09; &#xff0c; 最终的结果也是一个 boolean 值。 &&#xff1a;逻辑与&&&#xff1a;短路与|&#xff1a;逻辑或||&#xff1a;短路或&#xff01; 取反^&#xff1a;异或 二 逻辑运算规则 a&a…

K210基础实验——独立按键中断

前言 学习K210开发板的独立按键和中断功能 一、涉及到的外设资源是K210开发板上的BOOT按键和RGB灯 二、BOOT按键按下&#xff0c;MCU上连接BOOT的IO口变为低电平&#xff0c;松开后为高电平 三、引脚对应关系 BOOT : IO16 RGB灯&#xff1a; R:IO6 G:IO7 B:IO8 四、在…

【linux】多路径|Multipath I/O 技术

目录 简略 详细 什么是多路径? Multipath安装与使用 安装 使用 Linux下multipath软件介绍 附录 配置文件说明 其他解 简略 略 详细 什么是多路径? 普通的电脑主机都是一个硬盘挂接到一个总线上&#xff0c;这里是一对一的关系。 而到了分布式环境&#xff0c;主机和存储网络连…

NLP(5)-softmax和交叉熵

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 感觉全连接层就像一个中间层转换数据的形态的,或者说预处理数据&#xff1f; 代码 softmax就是把输出的y 归一化&#xff0c;把结果转化为概率值&#xff01;&#xff0c;在分类问题中很常见。 而交叉熵是一种损失函数&…