『MySQL 实战 45 讲』18 - 为什么这些SQL语句逻辑相同,性能却差异巨大

news2024/12/23 9:31:56

为什么这些SQL语句逻辑相同,性能却差异巨大

条件字段函数操作

  1. 创建一个 sql 表。该表为交易记录表,包含交易流水号(tradeid)、交易员 id(operator)、交易时间(t_modified)等字段
CREATE TABLE `tradelog` (
  `id` int(11) NOT NULL,
  `tradeid` varchar(32) DEFAULT NULL,
  `operator` int(11) DEFAULT NULL,
  `t_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `tradeid` (`tradeid`),
  KEY `t_modified` (`t_modified`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  1. 假设要求的是统计发生在所有年份中 7 月份的交易记录总数,可能会写出下面样式的 sql
select count(*) from tradelog where month(t_modified)=7;
  1. 由于函数计算,不会走索引,t_modified 的索引如图

在这里插入图片描述
4. 对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能
5. 优化器可以选择遍历主键索引,也可以选择遍历索引 t_modified,优化器对比索引大小后发现,索引 t_modified 更小,遍历这个索引比遍历主键索引来得更快。因此最终还是会选择索引 t_modified。但是这里是全索引扫描
在这里插入图片描述
6. 即使对于对于不改变有序性的函数,优化器也不会考虑使用索引(除非计算是在函数入参),例如

select * from tradelog where id + 1 = 10000
# 函数入参计算,这样才能用索引
# where id = 10000 -1

隐式类型转换

  1. 下面语句需要进行隐式转换,因为 tradeid 的字段类型是 varchar(32),而输入的参数却是整型,需要全表扫描
select * from tradelog where tradeid=110717;
  1. 对于优化器来说,这个语句相当于
select * from tradelog where  CAST(tradid AS signed int) = 110717;
  1. 这就说明了,这条语句触发了上面的规则:对索引字段做函数操作,优化器会放弃走树搜索功能

隐式字符编码转换

  1. 创建另外一个表,用于记录交易的操作细节,同时插入一些数据
CREATE TABLE `trade_detail` (
  `id` int(11) NOT NULL,
  `tradeid` varchar(32) DEFAULT NULL,
  `trade_step` int(11) DEFAULT NULL, /*操作步骤*/
  `step_info` varchar(32) DEFAULT NULL, /*步骤信息*/
  PRIMARY KEY (`id`),
  KEY `tradeid` (`tradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into tradelog values(1, 'aaaaaaaa', 1000, now());
insert into tradelog values(2, 'aaaaaaab', 1000, now());
insert into tradelog values(3, 'aaaaaaac', 1000, now());

insert into trade_detail values(1, 'aaaaaaaa', 1, 'add');
insert into trade_detail values(2, 'aaaaaaaa', 2, 'update');
insert into trade_detail values(3, 'aaaaaaaa', 3, 'commit');
insert into trade_detail values(4, 'aaaaaaab', 1, 'add');
insert into trade_detail values(5, 'aaaaaaab', 2, 'update');
insert into trade_detail values(6, 'aaaaaaab', 3, 'update again');
insert into trade_detail values(7, 'aaaaaaab', 4, 'commit');
insert into trade_detail values(8, 'aaaaaaac', 1, 'add');
insert into trade_detail values(9, 'aaaaaaac', 2, 'update');
insert into trade_detail values(10, 'aaaaaaac', 3, 'update again');
insert into trade_detail values(11, 'aaaaaaac', 4, 'commit');
  1. 查询 id=2 的交易的所有操作步骤信息
  • 第一行显示优化器会先在交易记录表 tradelog 上查到 id=2 的行,这个步骤用上了主键索引,rows=1 表示只扫描一行
  • 第二行 key=NULL,表示没有用上交易详情表 trade_detail 上的 tradeid 索引,进行了全表扫描
select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2; /*语句Q1*/

在这里插入图片描述
3. Q1 语句的执行过程
在这里插入图片描述

  • (1)是根据 id 在 tradelog 表里找到 L2 这一行
  • (2)是从 L2 中取出 tradeid 字段的值
  • (3)是根据 tradeid 值到 trade_detail 表中查找条件匹配的行。explain 的结果里面第二行的 key=NULL 表示的就是,这个过程是通过遍历主键索引的方式,一个一个地判断 tradeid 的值是否匹配
  1. 问题就出在第 3 步,单独把这一步变成 SQL 语句的话,如下
select * from trade_detail where tradeid=$L2.tradeid.value; 
  1. 其中 $L2.tradeid.value 的字符集是 utf8mb4,字符集 utf8mb4 是 utf8 的超集,MySQL 内部的操作是,先把 utf8 字符串转成 utf8mb4 字符集,再做比较
  2. 也就是说,实际上这个语句等同于下面这个写法
select * from trade_detail  where CONVERT(traideid USING utf8mb4)=$L2.tradeid.value; 
  1. 对索引字段做函数操作,优化器会放弃走树搜索功能。字符集不同只是条件之一,连接过程中要求在被驱动表的索引字段上加函数操作,是直接导致对被驱动表做全表扫描的原因
  2. 换个需求,如果是“查找 trade_detail 表里 id=4 的操作,对应的操作者是谁”
select l.operator from tradelog l , trade_detail d where d.tradeid=l.tradeid and d.id=4;

在这里插入图片描述
9. 这次的第 3 步语句相当于

select operator from tradelog  where traideid =$R4.tradeid.value; 
  1. 按照转换规则,实际是在输入参数上使用函数,所以能使用索引
select operator from tradelog  where traideid =CONVERT($R4.tradeid.value USING utf8mb4); 
  1. 所以,如果要使查 detail 表可以使用上索引,要不就修改字段的编码,要不就强制转换 tradeid 为 uft8
# 修改字段为 utf8mb4 
alter table trade_detail modify tradeid varchar(32) CHARACTER SET utf8mb4 default null;
# 强制转换 tradeid 为 uft8
select d.* from tradelog l , trade_detail d where d.tradeid=CONVERT(l.tradeid USING utf8) and l.id=2; 
  1. 总结:对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能

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

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

相关文章

Python版本管理工具-pyenv

Pyenv是一个Python版本管理工具。 Pyenv允许用户在同一台机器上安装多个版本的Python,并能够轻松切换使用这些版本。 一、安装 Mac下直接使用Homebrew安装 # 更新 Homebrew 的软件列表 brew update # 安装pyenv brew install pyenv# 验证是否安装成功 pyenv -v# …

【水文】LLM 成文测试|Agent AI智能体的未来:技术进步与创新

参与活动:#Agent AI智能体的未来# Agent AI智能体的未来征文活动介绍 随着Agent AI智能体的智能化水平不断提高,它们在未来社会中的角色、发展路径以及可能带来的挑战也引起了广泛关注。快来分享一下你的看法吧~ 活动时间 4月29日-5月13日 内容要求 1、文…

《深入解析Windows操作系统》第5章节学习笔记

1、每个Windows进程都是由一个执行体进程EPROCESS结构来表示的,EPROCESS和相关数据结构位于系统空间,但是进程环境控制块PEB是个例外,它位于进程空间地址中(因为它包含了一些需要由用户模式代码来修改的信息)。对于每一…

jvm面试题30问

什么是JVM的跨平台? 什么是JVM的语言无关性? 什么是JVM的解释执行 什么是JIT? JIT:在Java编程语言和环境中,即时编译器(JIT compiler,just-in-time compiler)是一个把Java的字节码(…

基于springboot实现英语知识应用网站系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现英语知识应用网站系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了英语知识应用网站的开发全过程。通过分析英语知识应用网站管理的不足,创建了一个计算机管理英语知识应…

Mysql中索引的概念

索引相关概念 基础概念: 在MySQL中,索引是一种数据结构,用于加快数据库查询的速度和性能。索引可以帮助MySQL快速定位和访问表中的特定数据,就像书籍的索引一样,通过存储指向数据行的指针,可以快速…

cmake的使用方法: 编译生成库文件

一. 简介 前面文章学习了针对单个 .c文件,cmake 工具是如何编译的? 针对包含多个 .c文件,cmake工具又是如何编译的?文章如下: cmake的使用方法: 单个源文件的编译-CSDN博客 cmake的使用方法: 多个源文件的编译-CS…

Allegro如何删除死铜

Allegro如何删除死铜 敷铜说明 敷铜后铜皮会避让与自己不同的信号,避让后有的铜皮就会变成很小一块,这个最小形状的设置如下, 首先点击: 然后选中对应的铜皮: 在鼠标右键,选择“Parameters…” 改变上图红色框中的数值就能设置最小死铜的大小。 删除死铜的方法 1、首…

设计模式之装饰者模式DecoratorPattern(四)

一、概述 装饰者模式(Decorator Pattern)是一种用于动态地给一个对象添加一些额外的职责的设计模式。就增加功能来说,装饰者模式相比生成子类更为灵活。装饰者模式是一种对象结构型模式。 装饰者模式可以在不改变一个对象本身功能的基础上增…

前端开发报错:Extension context invalidated

这个错误一般是由浏览器的插件导致的 直接卸载 就没有问题了 注意检查 可能不是你自己的代码问题哦~

【如何使用SSH密钥验证提升服务器安全性及操作效率】(优雅的连接到自己的linux服务器)

文章目录 一、理论基础(不喜欢这部分的可直接看具体操作)1.为什么要看本文(为了zhuangbility)2.为什么要用密钥验证(更安全不易被攻破)3.密码验证与密钥验证的区别 二、具体操作1.生成密钥对1.1抉择&#x…

DataTrove:一款针对大规模文本数据的处理、过滤和消除重复数据工具

关于DataTrove DataTrove是一款针对大规模文本数据的处理、过滤和消除重复数据工具,该工具可以通过提供一组平台无关的可定制管道处理块,帮助广大研究人员从各种复杂脚本中解放出来,同时还允许我们轻松添加自定义功能。 DataTrove所实现的数…

再生龙clonezilla使用方法

目录 本文相关内容的介绍服务器窗口重定向引导进入再生龙系统检查本机操作系统的引导模式 再生龙基础功能选择选择 device-image选择ssh_server 网络配置ssh_server 配置ssh_server 镜像存储路径 再生龙抓取操作系统抓取镜像的命名 再生龙恢复操作系统拉取镜像的选择 本文相关内…

OpenCV4.9的点多边形测试(65)

返回:OpenCV系列文章目录(持续更新中......) 上一篇:OpenCV的图像矩(64) 下一篇:OpenCV4.9的基于距离变换和分水岭算法的图像分割(66) Point Polygon Test(点多边形测试)是 OpenCV 库中的一个功能,用于判…

Windows安装mysql8.0.20

目录 1.下载安装包mysql8.0.20 2.配置MySQL环境变量 3.开始安装 ​编辑4.打开cmd命令行 5.Navicat测试连接 1.下载安装包mysql8.0.20 MySQL :: Download MySQL Community Server (Archived Versions) 2.配置MySQL环境变量 3.开始安装 将压缩包安装到指定路径 编辑my.ini文件…

一起Talk Android吧(第五百五十八回:lombok用法)

文章目录 1. 概述2. 使用方法3. 内容总结 各位看官们大家好,上一回中介绍了如何获取文件读写权限的知识,本章回中将介绍lombok相关的知识。闲话休提,言归正转,让我们一起Talk Android吧! 1. 概述 这是一个java库,用来…

[系统安全] 六十.威胁狩猎 (1)APT攻击检测及防御与常见APT组织的攻击案例分析

您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列。因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全、逆向分析和恶意代码检测,“系统安全”系列文章会更加聚焦,更加系…

踏上R语言之旅:解锁数据世界的神秘密码(五)

线性与非线性模型及R使用 文章目录 线性与非线性模型及R使用一、数据的分类与模型选择1.变量的取值类型 二、广义线性模型广义线性模型概述Logistic模型 总结 一、数据的分类与模型选择 1.变量的取值类型 因变量记为y,解释变量记为x1,x2,… 因变量y一般…

Coursera: An Introduction to American Law 学习笔记 Week 05: Criminal Law

An Introduction to American Law 本文是 https://www.coursera.org/programs/career-training-for-nevadans-k7yhc/learn/american-law 这门课的学习笔记。 文章目录 An Introduction to American LawInstructors Week 05: Criminal LawKey Criminal Law TermsSupplemental Re…

边沿JK触发器

边沿JK触发器 电路组成 & 逻辑符号 工作原理 Q n 1 D Q^{n1}D Qn1D J Q n ‾ K Q n ‾ \overline{\overline{JQ^n}KQ^n} JQn​KQn​ ( J Q n ) ( K ‾ Q n ‾ ) (JQ^n)(\overline{K}\overline{Q^n}) (JQn)(KQn​) J K ‾ J Q n ‾ K ‾ Q n Q n ‾ Q n J\over…