【MySQL进阶】SQL优化

文章目录

  • SQL 优化
    • 主键优化
      • 数据组织方式
      • 页分裂
      • 页合并
      • 主键设计原则
    • insert优化
    • order by优化
    • group by优化
    • limit优化
    • count优化

SQL 优化

主键优化

数据组织方式

  • 在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表

image.png

  • 在InnoDB引擎中,数据行是记录在逻辑结构 page 页中的,而每一个页的大小是固定的,默认16K。 那也就意味着, 一个页中所存储的行也是有限的,如果插入的数据行row在该页存储不小,将会存储 到下一个页中,页与页之间会通过指针连接。

页分裂

每个页的大小书固定的,页可以为空,也可以填充一半,也可以填充100%,每个页包含了2-N行数据(如果一行数据过大,会行 溢出),根据主键排列

  • 按主键自增的方式插入数据。

①. 从磁盘中申请页, 主键顺序插入
②. 第一个页没有满,继续往第一页插入
image.png
③. 当第一个也写满之后,再写入第二个页,页与页之间会通过指针连接
image.png
④. 当第二页写满了,再往第三页写入
image.png

  • 主键乱序插入效果

①. 假如1#,2#页都已经写满了,存放了如图所示的数据
image.png
②. 此时再插入id为50的记录,就会发生页分裂。因为需要顺序存储,按照顺序,应该存储在47之后,
但是该页已经满了,则需要新申请一个3#页,将1#页后一半的数据,移动到3#页,然后在3#页,插入50。
image.png
重新设置链表指针
image.png

上述现象就叫做页分裂,是比较耗费性能的。

页合并

假如表中已有数据的索引结构(叶子节点)如下:
image.png
当我们对已有数据进行删除时,具体的效果如下:
当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并且它的空间
变得允许被其他记录声明使用。
image.png
当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前
或后)看看是否可以将两个页合并以优化空间使用。
image.png

上述现象就叫做页合并

主键设计原则

  • 满足业务需求的情况下,尽量降低主键的长度。
  • 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。
  • 尽量不要使用UUID做主键或者是其他自然主键,如身份证号。
  • 业务操作时,避免对主键的修改。

insert优化

如果我们需要一次性往数据库表中插入多条记录,可以从以下四个方面进行优化

  • 优化方案一:批量插入数据
    • 假如一条一条的插入数据,每次插入数据,都需要建立连接,很费时间
  • 优化方案二:手动控制事务
    • MySQL默认执行一条语句提交一次事务,耗时
  • 优化方案三:主键顺序插入
    • 因为 InnoDB 类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。
    • 主键是否连续对性能影响不大,只要是递增的就可以,比如雪花算法产生的 ID 不是连续的,但是是递增的,因为递增可以让主键索引尽量地保持顺序插入,避免了页分裂,因此索引更紧凑。
  • 优化方案四:关闭唯一性校验。
    • 在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验;导入结束后执行 SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。

如果一次性需要插入大批量数据(比如: 几百万的记录),使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入。操作如下:

-- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
-- 执行load指令将准备好的数据,加载到表结构中
load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;

image.png

order by优化

MySQL的排序,有两种方式:

  • Using filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
  • Using index : 通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高。

对于以上的两种排序方式,Using index的性能高,而Using filesort的性能低,我们在优化排序操作时,尽量要优化为 Using index。

测试:目前tb_user只有一个主键索引

  1. 执行排序SQLexplain select id,age,phone from tb_user order by age, phoneimage.png

由于age、phone都没有索引,可以看到为Using filesort,需要到内存中重新排序。

  1. 创建索引create index idx_user_age_phone_aa on tb_user(age,phone);
  2. 创建索引后,根据age, phone进行升序排序

explain select id,age,phone from tb_user order by age,phone;
image.png
可以看到建立索引之后,再次进行排序查询,就由原来的Using filesort, 变为了 Using index,性能
就是比较高的了。(仍然遵循最左前缀原则)
优化注意以下几点:
A. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
B. 尽量使用覆盖索引。
C. 多字段排序, 一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。

  • 若索引两个字段都是升序,则排序时两字段升序或降序都会Using index。
  • 索引字段的排序规则需要和order by后面字段的排序规则一样。

D. 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小

group by优化

GROUP BY 也会进行排序操作,与 ORDER BY 相比,GROUP BY 主要只是多了排序之后的分组操作,所以在 GROUP BY 的实现过程中,与 ORDER BY 一样也可以利用到索引

  • 分组查询:
DROP INDEX idx_emp_age_salary ON emp;
EXPLAIN SELECT age,COUNT(*) FROM emp GROUP BY age;

Using temporary:表示 MySQL 需要使用临时表(不是 sort buffer)来存储结果集,常见于排序和分组查询

  • 查询包含 GROUP BY 但是用户想要避免排序结果的消耗, 则可以执行 ORDER BY NULL 禁止排序:EXPLAIN SELECT age,COUNT(*) FROM emp GROUP BY age ORDER BY NULL;
  • 创建索引:索引本身有序,不需要临时表,也不需要再额外排序

CREATE INDEX idx_emp_age_salary ON emp(age, salary);

  • 数据量很大时,使用 SQL_BIG_RESULT 提示优化器直接使用直接用磁盘临时表

limit优化

一个常见的问题是 LIMIT 200000,10,此时需要 MySQL 扫描前 200010 记录并进行排序,仅仅返回 200000 - 200010 之间的记录,其他记录丢弃,查询排序的代价非常大

  • 分页查询:EXPLAIN SELECT * FROM tb_user_1 LIMIT 200000,10;
  • 优化方式一:内连接查询,在索引列 id 上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容(id是索引列,查询速度较快)
  • EXPLAIN SELECT * FROM tb_user_1 t,(SELECT id FROM tb_user_1 ORDER BY id LIMIT 200000,10) a WHERE t.id = a.id;
  • 优化方式二:方案适用于主键自增的表,可以把 LIMIT 查询转换成某个位置的查询
EXPLAIN SELECT * FROM tb_user_1 WHERE id > 200000 LIMIT 10;         -- 写法 1
EXPLAIN SELECT * FROM tb_user_1 WHERE id BETWEEN 200000 and 200010; -- 写法 2

count优化

在不同的 MySQL 引擎中,count(*) 有不同的实现方式:

  • MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高,但不支持事务
  • InnoDB 表执行 count(*) 会遍历全表,虽然结果准确,但会导致性能问题

解决方案:

  • 计数保存在 Redis 中,但是更新 MySQL 和 Redis 的操作不是原子的,会存在数据一致性的问题
  • 计数直接放到数据库里单独的一张计数表中,利用事务解决计数精确问题:会话 B 的读操作在 T3 执行的,这时更新事务还没有提交,所以计数值加 1 这个操作对会话 B 还不可见,因此会话 B 查询的计数值和最近 100 条记录,返回的结果逻辑上就是一致的并发系统性能的角度考虑,应该先插入操作记录再更新计数表,因为更新计数表涉及到行锁的竞争,先插入再更新能最大程度地减少事务之间的锁等待,提升并发度

count 函数的按照效率排序:count(字段) < count(主键id) < count(1) ≈ count(),所以建议尽量使用 count()

  • count(主键 id):InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来返回给 Server 层,Server直接就按行累加(主键不可能为空)
  • count(1):InnoDB 引擎遍历整张表但不取值,Server 层对于返回的每一行,放一个数字 1 进去,直接按行累加
  • count(字段):如果这个字段是定义为 not null 的话,一行行地从记录里面读出这个字段,直接按行累加;如果这个字段定义允许为 null,那么执行的时候,还要把值取出来,再判断一下,不是 null 才累加。
  • count(*):不取值,按行累加。

## update优化 `update course set name = 'javaEE' where name = 'jack' ; `
  1. 如果name是索引字段,在该行数据上添加行锁。其他线程可以修改其他行数据。
  2. 如果name不是索引字段或者索引失效了,则直接在该张表上添加表锁。其他线程不可以修改其他行数据。
  3. 所以where后面的字段尽量添加索引。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【5G 接口协议】N2接口协议NGAP(NG Application Protocol)介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

PIG框架学习3——Redisson 实现业务接口幂等

零、前言 ​ 业务接口幂等问题是在开发中遇到的&#xff0c;如果对业务接口代码不进行幂等控制&#xff0c;并且在前端没有对请求进行限制的情况下&#xff0c;可能会出现多次对接口调用&#xff0c;导致错误异常的发生。就上述情况&#xff0c;对PIGX自带的业务接口幂等实现进…

无法找到mfc100.dll的解决方法分享,如何快速修复mfc100.dll文件

在日常使用电脑时&#xff0c;我们可能会碰到一些系统错误提示&#xff0c;比如“无法找到mfc100.dll”的信息。这种错误通常会阻碍代码的执行或某些应用程序的启动。为了帮助您解决这一问题&#xff0c;本文将深入探讨其成因&#xff0c;并提供几种不同的mfc100.dll解决方案。…

lv14 内核定时器 11

一、时钟中断 硬件有一个时钟装置&#xff0c;该装置每隔一定时间发出一个时钟中断&#xff08;称为一次时钟嘀嗒-tick&#xff09;&#xff0c;对应的中断处理程序就将全局变量jiffies_64加1 jiffies_64 是一个全局64位整型, jiffies全局变量为其低32位的全局变量&#xff0…

三.Winform使用Webview2加载本地HTML页面

Winform使用Webview2加载本地HTML页面 往期目录创建Demo2界面创建HTML页面在Demo2窗体上添加WebView2和按钮加载HTML查看效果 往期目录 往期相关文章目录 专栏目录 创建Demo2界面 经过前面两小节 一.Winform使用Webview2(Edge浏览器核心) 创建demo(Demo1)实现回车导航到指定…

用立创EDA(专业版)设计原理图

简介 立创EDA&#xff0c;国产的EDA工具。 下载 官方下载链接 下载后&#xff0c;直接一直下一步&#xff0c;最后安装提示免费激活即可。 注意 嘉立创EDA专业版的数据和立创EDA标准版的数据不互通&#xff0c; 常用原理图绘制设置 开发流程 新建工程绘制PCB 文件->新…

【QT+QGIS跨平台编译】之一:【sqlite+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、sqlite3介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、sqlite3介绍 SQLite是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的&…

【数据结构】 双链表的基本操作 (C语言版)

目录 一、双链表 1、双链表的定义&#xff1a; 2、双链表表的优缺点&#xff1a; 二、双链表的基本操作算法&#xff08;C语言&#xff09; 1、宏定义 2、创建结构体 3、双链表的初始化 4、双链表表插入 5、双链表的查找 6、双链表的取值 7、求双链表长度 8、双链表…

2023年12月 Scratch 图形化(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch图形化等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 观察下列每个圆形中的四个数,找出规律,在括号里填上适当的数?( ) A:9 B:17 C:21 D:5 答案:C 左上角的数=下面两个数的和+右上角的数

142.环形链表 II 、141. 环形链表(附带源码)

目录 一、142问题的分析与解决&#xff1a; 二、怎么做&#xff1f; 三、142代码 四、141代码 一、142问题的分析与解决&#xff1a; 核心&#xff1a;定义快慢指针&#xff1a;slow、fast 思路是当快指针fast进环时&#xff0c;慢指针slow一定没有进环 这个时候就是就变…

flink基本概念

1. Flink关键组件: 这里首先要说明一下“客户端”。其实客户端并不是处理系统的一部分&#xff0c;它只负责作业的提交。具体来说&#xff0c;就是调用程序的 main 方法&#xff0c;将代码转换成“数据流图”&#xff08;Dataflow Graph&#xff09;&#xff0c;并最终生成作业…

Leetcode刷题笔记题解(C++):LCR 174. 寻找二叉搜索树中的目标节点

思路&#xff1a;二叉搜索树的中序遍历是有序的从大到小的&#xff0c;故得出中序遍历的结果&#xff0c;即要第cnt大的数为倒数第cnt的数 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeN…

新闻每天都在更新,那网页上的新闻页面是怎么使用Dreamweaver制作的?

新闻每天都在更新&#xff0c;那网页上的新闻页面是怎么使用Dreamweaver制作的&#xff1f; 新闻有很多种&#xff0c;但大多数结构都差不多&#xff0c;我们就先做一个简单的新闻页面&#xff0c;如图1中画圈圈的新闻内容。 图1 案例实现 新闻页面一般由四个部分构成&#…

【spring】代码生成器

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;spring ⛺️稳中求进&#xff0c;晒太阳 代码生成器&#xff08;本质IO流&#xff09; 在mybatis的逆向工程生成model和mapper接口和xml文件后&#xff0c;还需要反复的写Service的接口和…

何为PyTorch?

PyTorch的名字来源于它的功能和设计哲学。"Py"代表Python&#xff0c;因为PyTorch是一个基于Python的深度学习库&#xff0c;它充分利用了Python语言的灵活性和易用性&#xff0c;为开发者提供了简洁而强大的接口。“Torch”则代表其前身—— Torch&#xff0c;这是一…

7.前端--CSS-复合选择器

1.什么是复合选择器 复合选择器是由两个或多个基础选择器&#xff0c;通过不同的方式组合而成的&#xff0c;可以更准确、更高效的选择目标元素&#xff08;标签&#xff09; 常用的复合选择器包括&#xff1a;后代选择器、子选择器、并集选择器、伪类选择器等等 2.后代选择器 …

Opencv轮廓检测运用与理解

目录 引入 基本理解 加深理解 ①比如我们可以获取我们的第一个轮廓,只展示第一个轮廓 ②我们还可以用一个矩形把我们的轮廓给框出来 ③计算轮廓的周长和面积 引入 顾名思义,就是把我们图片的轮廓全部都描边出来 也就是我们在日常生活中面部识别的时候会有一个框,那玩意就…

wayland(wl_shell) + egl + opengles 最简实例

文章目录 前言一、ubuntu 上相关环境准备1. ubuntu 上安装 weston2. 确定ubuntu 上安装的opengles 版本3. 确定安装的 weston 是否支持 wl_shell 接口二、窗口管理器接口 wl_shell 介绍二、代码实例1.egl_wayland_demo.c2. 编译和运行2.1 编译2.2 运行总结参考资料前言 本文主…

如何才能拥有比特币 - 01 ?

如何才能拥有BTC 在拥有 BTC 之前我们要先搞明白 BTC到底保存在哪里&#xff1f;我的钱是存在银行卡里的&#xff0c;那我的BTC是存在哪里的呢&#xff1f; BTC到底在哪里&#xff1f; 一句话概括&#xff0c;BTC是存储在BTC地址中&#xff0c;而且地址是公开的&#xff0c;…

webpack-dev-server原理解析及其中跨域解决方法

webpack proxy ,就是 webpack 提供的解决跨域的方案。其基本行为是接受客户端发送的请求后转发给其他的服务器&#xff0c;目的是为了解决在开发模式下的跨域问题。 原理 webpack中的proxy 工作原理是利用了 http-proxy-middleware 这个http 代理中间件&#xff0c;实现将请求…