MySQL SQL 优化专题

MySQL SQL 优化专题

1. 插入数据优化

-- 普通插入(不推荐)
INSERT INTO tb_user VALUES(1,'tom');
INSERT INTO tb_user VALUES(2,'cat');
INSERT INTO tb_user VALUES(3,'jerry');-- 优化方案1:批量插入(推荐,不建议超过1000条,500-1000较为合适)
INSERT INTO tb_user VALUES(1,'tom'), (2,'cat'), (3,'jerry');-- 优化方案2:手动事务提交(适用于大数据量)
start transaction;
INSERT INTO tb_user VALUES(1,'tom');
INSERT INTO tb_user VALUES(2,'cat');
commit;-- 优化方案3:主键顺序插入(减少页分裂)
-- 有序ID:1,2,3,4... 
-- 无序ID:3,1,4,2...-- 优化方案4:LOAD命令(百万级数据)
-- 客户端连接服务端时,加上参数  -–local-infile
mysql –-local-infile  -u  root  -p
-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set  global  local_infile = 1;
-- 执行load指令将准备好的数据,加载到表结构中
-- 语法:LOAD DATA LOCAL INFILE '文件路径' INTO TABLE 表名; 
load  data  local  infile  '/root/sql1.log'  into  table  tb_user  fields  terminated  by  ','  lines  terminated  by  '\n' ; 

原理说明

  • 批量插入减少事务提交次数
  • 顺序插入可减少页分裂概率
  • LOAD指令比INSERT快约20倍

2. 主键优化

(1)数据组织方式

在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表 (index organized table IOT)。

  • InnoDB采用B+树索引,数据存储在叶子节点
  • 页分裂(离散插入导致)和页合并(删除数据后触发)

在这里插入图片描述

行数据,都是存储在聚集索引的叶子节点上的。InnoDB的逻辑结构图:

在这里插入图片描述

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

**(2). 页分裂 **

页可以为空,也可以填充一半,也可以填充100%。每个页至少包含了2行数据(只有一行数据就等于退化成链表了)(如果一行数据过大,会行溢出),根据主键排列。

A. 主键顺序插入效果

①. 从磁盘中申请页, 主键顺序插入

在这里插入图片描述

②. 第一个页没有满,继续往第一页插入

在这里插入图片描述

③. 当第一个也写满之后,再写入第二个页,页与页之间会通过指针连接

在这里插入图片描述

④. 当第二页写满了,再往第三页写入

在这里插入图片描述

B. 主键乱序插入效果

①. 加入1#,2#页都已经写满了,存放了如图所示的数据

在这里插入图片描述

②. 此时再插入id为50的记录,我们来看看会发生什么现象 ?

会再次开启一个页,写入新的页中吗?

在这里插入图片描述

不会。因为,索引结构的叶子节点是有顺序的。按照顺序,应该存储在47之后。

在这里插入图片描述

但是47所在的1#页,已经写满了,存储不了50对应的数据了。 那么此时会开辟一个新的页 3#。

在这里插入图片描述

但是并不会直接将50存入3#页,而是会将1#页后一半的数据,移动到3#页,然后在3#页,插入50。

在这里插入图片描述

移动数据,并插入id为50的数据之后,那么此时,这三个页之间的数据顺序是有问题的。 1#的下一个 页,应该是3#, 3#的下一个页是2#。 所以,此时,需要重新设置链表指针。(连接过程类似双向链表的插入过程)
在这里插入图片描述

上述的这种现象,称之为 “页分裂”,是比较耗费性能的操作。

3). 页合并

目前表中已有数据的索引结构(叶子节点)如下:
在这里插入图片描述

当我们对已有数据进行删除时,具体的效果如下:

当删除一行记录时,**实际上记录并没有被物理删除,只是记录被标记(flaged)**为删除并且它的空间 变得允许被其他记录声明使用。

在这里插入图片描述

当我们继续删除2#的数据记录
在这里插入图片描述

当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
在这里插入图片描述

删除数据,并将页合并之后,再次插入新的数据21,则直接插入3#页
在这里插入图片描述

这个里面所发生的合并页的这个现象,就称之为 “页合并”。

知识小贴士: MERGE_THRESHOLD(threshold:阈值):合并页的阈值,可以自己设置,在创建表或者创建索引时指定。

4). 主键设计原则

  1. 满足业务需求情况下,尽量降低主键长度
  2. 插入数据时尽量选择顺序插入,使用AUTO_INCREMENT主键
  3. 尽量不要使用UUID(无序,插入可能产生页分裂现象,影响性能)或其他自然主键(如身份证号:长度比较长,检索时会浪费大量的磁盘IO时间)
  4. 避免对主键进行修改(修改主键还需要修改对应的索引)

3. ORDER BY 优化

MySQL的排序,有两种方式:

Using filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。

Using index : 通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要 额外排序,操作效率高。

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

-- 需要优化的查询(出现Using filesort)
explain select  id,age,phone from tb_user order by age ;
explain select  id,age,phone from tb_user order by age, phone ;
--由于 age, phone 都没有索引,所以此时再排序时,出现Using filesort, 排序性能较低。-- 创建索引
CREATE INDEX idx_age_phone ON tb_user(age, phone);--创建索引后,根据age, phone进行升序排序
-- 优化后查询(Using index)
explain select  id,age,phone from tb_user order by age, phone ;
--建立索引之后,再次进行排序查询,就由原来的Using filesort, 变为了 Using index,性能就是比较高的了。
--根据age, phone进行降序一个升序,一个降序
explain select  id,age,phone from tb_user order by age desc , phone desc ;
--因为创建索引时,如果未指定顺序,默认都是按照升序排序的,而查询时,一个升序,一个降序,此时
--就会出现Using filesort。

为了解决上述的问题,我们可以创建一个索引,这个联合索引中 age 升序排序,phone 倒序排序。

创建联合索引(age 升序排序,phone 倒序排序)

 create  index  idx_user_age_phone_ad  on  tb_user(age asc ,phone desc);

优化后查询(Using index)。

升序/降序联合索引结构图示:
在这里插入图片描述

在这里插入图片描述

--根据phone,age进行升序排序,phone在前,age在后。(易错细节)
explain select  id,age,phone from tb_user order by phone , age;
--排序时,也需要满足最左前缀法则,否则也会出现 filesort。因为在创建索引的时候, age是第一个
--字段,phone是第二个字段,所以排序时,也就该按照这个顺序来,否则就会出现 Using filesort。

排序类型

  • Using index:直接通过索引返回数据(性能最佳)
  • Using filesort:需要将结果集加载到内存排序(需要优化)

order by优化原则:

A. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。(where 后的连表条件只要存在即可,无所谓顺序,但order by后面的书写有顺序要求)

B. 尽量使用覆盖索引。(减少使用select * ,不用回表)

C. 多字段排序, 一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。

D. 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小 sort_buffer_size(默认256k)。

4. GROUP BY 优化

-- 未优化(出现Using temporary)
EXPLAIN SELECT profession, COUNT(*) FROM tb_user 
GROUP BY profession;-- 创建索引后优化
CREATE INDEX idx_pro_age_sta ON tb_user(profession,age,status);
EXPLAIN SELECT profession, COUNT(*) FROM tb_user 
GROUP BY profession; -- 使用索引

优化方法

A. 在分组操作时,可以通过索引来提高效率。

B. 分组操作时,索引的使用也是满足最左前缀法则的。

5. LIMIT 优化

在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低。

我们一起来看看执行limit分页查询耗时对比:
在这里插入图片描述

通过测试我们会看到,越往后,分页查询效率越低,这就是分页查询的问题所在。 因为,当在进行分页查询时,如果执行 limit 2000000,10 ,此时需要MySQL排序前2000010 记 录,仅仅返回 2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。

(因为叶子排序是双链表,要依次遍历,越向后时间越长。)

优化思路: 一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。

explain   select  *  from  tb_sku  t  ,  (select  id  from  tb_sku  order  by  id 
limit  2000000,10)  a  where t.id  =  a.id;
-- 低效写法(耗时随偏移量增加)
SELECT * FROM tb_sku LIMIT 9000000,10;-- 优化方案:记录上次查询的最大ID
SELECT * FROM tb_sku WHERE id > 9000000 LIMIT 10;-- 子查询优化(需覆盖索引)
SELECT * FROM tb_sku t, 
(SELECT id FROM tb_sku ORDER BY id LIMIT 9000000,10) a 
WHERE t.id = a.id;

优化原理

  • 避免全表扫描,使用索引覆盖
  • 使用ID分段查询替代大偏移量

6. COUNT 优化

 select  count(*)  from  tb_user ;

我们发现,如果数据量很大,在执行count操作时,是非常耗时的。

MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高; 但是如果是带条件的count,MyISAM也慢。

InnoDB 引擎就麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数 。

如果说要大幅度提升InnoDB表的count效率,主要的优化思路:

自己计数(可以借助于redis这样的数 据库进行,但是如果是带条件的count又比较麻烦了)。

count用法

count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加,最后返回累计值。

用法:count(*)、count(主键)、count(字段)、count(数字)
在这里插入图片描述

--按照效率排序的话,所以尽量使用count(*),因为专门做了优化。
count(字段)(需要做判断是否为空)< count(主键 id) < count(1)count(*)-- 统计有效数据条数
SELECT COUNT(1) FROM tb_user;  -- 推荐写法
SELECT COUNT(*) FROM tb_user;  -- 官方优化写法

不同COUNT区别

  • COUNT(字段):统计不为NULL的记录数
  • COUNT(主键):遍历主键索引
  • COUNT(1):不取值直接累加1
  • COUNT(*):MySQL优化过的特殊计数器

7. UPDATE 优化

回忆:InnoDB的三大特性:事务,外键,行级锁

​ start transaction; 或者是begin来开启事务;

我们主要需要注意一下update语句执行时的注意事项。

update  course  set  name = 'javaEE'  where  id  =  1 ;

在这里插入图片描述

当我们在执行更新的SQL语句时,会锁定id为1这一行的数据,然后事务提交之后,行锁释放。

但是当我们在执行如下SQL时。

update course set name = 'SpringBoot' where name = 'PHP' ;

在这里插入图片描述

name这个字段没有索引,此时加的就不再是行锁了,而是表锁。一旦锁表了,我们的并发性能就会降低!!!

当我们开启多个事务,在执行上述的SQL时,我们发现行锁升级为了表锁。 导致该update语句的性能大大降低。

InnoDB的行锁是针对索引加的锁,不是针对记录加的锁 ,并且该索引不能失效,否则会从行锁 升级为表锁 。

-- 使用索引字段更新(行级锁)
UPDATE tb_user SET name = 'zhangsan' WHERE id = 1;-- 无索引更新(表级锁,需要避免!)
UPDATE tb_user SET name = 'lisi' WHERE name = 'wangwu';

优化重点

  • 更新条件必须走索引,避免行锁升级为表锁
  • 事务要及时提交,减少锁持有时间

总结

优化类型核心方法典型案例
插入优化批量插入+手动事务提交+主键顺序插入万级数据使用LOAD DATA
主键优化自增主键+避免修改+尽量短UUID导致页分裂问题
ORDER BY尽量建立覆盖索引+避免filesort多字段排序注意索引顺序
GROUP BY利用索引减少临时表(多字段分组满足最左前缀法则)分组字段建立联合索引
LIMIT覆盖索引+子查询(使用ID分段替代大偏移量)百万级分页优化方案
COUNT优先使用COUNT(*)或COUNT(1)统计全表数据时避免COUNT(字段)
UPDATEWHERE条件必须走索引无索引更新导致表锁问题

通过以上优化手段,通常可以使MySQL查询性能提升1-3个数量级,特别是在大数据量场景下效果尤为显著。实际优化中需要结合EXPLAIN执行计划进行分析,针对性优化关键瓶颈点。

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

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

相关文章

【AI深度学习基础】NumPy完全指南进阶篇:核心功能与工程实践(含完整代码)

NumPy系列文章 入门篇进阶篇终极篇 一、引言 在掌握NumPy基础操作后&#xff0c;开发者常面临真实工程场景中的三大挑战&#xff1a;如何优雅地处理高维数据交互&#xff1f;如何在大规模计算中实现内存与性能的平衡&#xff1f;怎样与深度学习框架实现高效协同&#xff1f;…

Python学习第十八天之深度学习之Tensorboard

Tensorboard 1.TensorBoard详解2.安装3.使用4.图像数据格式的一些理解 后续会陆续在词博客上更新Tensorboard相关知识 1.TensorBoard详解 TensorBoard是一个可视化的模块&#xff0c;该模块功能强大&#xff0c;可用于深度学习网络模型训练查看模型结构和训练效果&#xff08;…

【GraphQL API 漏洞简介】

GraphQL API 漏洞简介 一、漏洞原理与分类二、漏洞检测方法三、典型利用方式四、工具推荐防御建议 GraphQL API 因其灵活性和高效性被广泛应用&#xff0c;但也因设计和实现缺陷存在多种安全风险。以下从漏洞原理、检测方法及利用方式三个维度进行详细分析&#xff1a; 一、漏洞…

Windows逆向工程入门之MASM数据结构使用

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 第一章&#xff1a;MASM数据定义体系精要 1.1 基础数据类型全景 1.1.1 整型数据规范 1.1.2 浮点数据编码 1.2 复合数据结构 1.2.1 多维数组定义 1.2.2 复杂结构体 第二章&#xf…

筑牢安全防线:工商业场所燃气泄漏防护新方案

燃气安全是企业经营不可逾越的生命线。在餐饮后厨、化工车间、酒店锅炉房等场所&#xff0c;可燃气体一旦泄漏&#xff0c;极易引发严重事故。如何实现精准监测、快速响应&#xff0c;成为工业及商业领域安全管理的核心诉求。旭华智能深耕安全监测领域&#xff0c;推出的工业及…

本地部署大数据集群前置准备

1. 设置VMware网段 虚拟网络编辑器——更改设置——选择VMnet8——子网改成192.168.88.0——NAT设置——网关设置为192.168.88.2 2. 下载CentOS操作系统 下载CentOS 7.6(1810)版本 3. 在VMware中安装CentOS操作系统 创建新的虚拟机——典型——安装光盘映像文件——输入账…

【蓝桥杯单片机】第十二届省赛

一、真题 二、模块构建 1.编写初始化函数(init.c) void Cls_Peripheral(void); 关闭led led对应的锁存器由Y4C控制关闭蜂鸣器和继电器 由Y5C控制 2.编写LED函数&#xff08;led.c&#xff09; void Led_Disp(unsigned char ucLed); 将ucLed取反的值赋给P0 开启锁存器…

PyCharm接入本地部署DeepSeek 实现AI编程!【支持windows与linux】

今天尝试在pycharm上接入了本地部署的deepseek&#xff0c;实现了AI编程&#xff0c;体验还是很棒的。下面详细叙述整个安装过程。 本次搭建的框架组合是 DeepSeek-r1:1.5b/7b Pycharm专业版或者社区版 Proxy AI&#xff08;CodeGPT&#xff09; 首先了解不同版本的deepsee…

CSS 系列之:grid 布局

基本概念 <template><div class"parent"><div class"box">p1-1</div><div class"box">p1-2</div><div class"box">p1-3</div></div><div class"parent"><…

数学软件Matlab下载|支持Win+Mac网盘资源分享

如大家所了解的&#xff0c;Matlab与Maple、Mathematica并称为三大数学软件。Matlab应用广泛&#xff0c;常被用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人&#xff0c;控制系统等领域。 Matlab将数值分析、矩阵计算、科学…

水仙花数(华为OD)

题目描述 所谓水仙花数&#xff0c;是指一个n位的正整数&#xff0c;其各位数字的n次方和等于该数本身。 例如153是水仙花数&#xff0c;153是一个3位数&#xff0c;并且153 13 53 33。 输入描述 第一行输入一个整数n&#xff0c;表示一个n位的正整数。n在3到7之间&#x…

物联网同RFID功能形态 使用场景的替代品

在物联网&#xff08;IoT&#xff09;和自动识别技术领域&#xff0c;除了RFID标签外&#xff0c;还有一些其他技术产品可以在形态和大小上与RFID标签相似&#xff0c;同时提供类似或更强大的功能。以下是几种能够替代RFID标签的产品&#xff1a; 一、NFC标签 NFC&#xff08;…

03.03 QT

1.在注册登录的练习里面&#xff0c;追加一个QListwidget 项目列表 要求:点击注册之后&#xff0c;将账号显示到 1istwidget上面去 以及&#xff0c;在listwidget中双击某个账号的时候&#xff0c;将该账号删除 Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWi…

c++ cout详解

在 C++ 中,cout 是标准输出流对象,用于向控制台(或标准输出设备)输出数据。它是 iostream 库的核心组件之一,与 << 流插入运算符配合使用。 一、基本用法 1. 头文件和命名空间 #include <iostream> // 必须包含的头文件 using namespace std; // 命名空间(…

深入解析 .NET Core 的应用启动流程

随着 .NET Core 的发展&#xff0c;它逐渐成为构建跨平台、高性能 Web 应用的首选框架。了解 .NET Core 的应用启动流程是开发者成功使用该框架的关键&#xff0c;尤其是在调试、优化和部署时。本文将深入探讨 .NET Core 的应用启动过程&#xff0c;从创建 Web 主机、配置服务、…

(十二)基于 Vue 3 和 Mapbox GL 实现的坐标拾取器组件示例

下面是一个基于 Vue 3 和 Mapbox GL 实现的坐标拾取器组件示例: <template><div class="map-container"><div ref="mapContainer" class="map"></div><div class="coordinates-box"><div v-if=&qu…

LINUX网络基础 - 网络编程套接字,UDP与TCP

目录 前言 一. 端口号的认识 1.1 端口号的作用 二. 初识TCP协议和UDP协议 2.1 TCP协议 TCP的特点 使用场景 2.2 UDP协议 UDP的特点 使用场景 2.3 TCP与UDP的对比 2.4 思考 2.5 总结 三. 网络字节序 3.1 网络字节序的介绍 3.2 网络字节序思考 四. socket接口 …

歌曲分类和流行度预测

1. 项目介绍 本项目从kaggle平台上下载了数据集&#xff0c;该数据集包含了3万多首来自Spotify API 的歌曲&#xff0c;共有23个特征。首先对数据集进行预处理&#xff0c;如重复行、缺失值、标准化处理等。再对预处理后的数据进行探索性分析&#xff0c;观察各变量的分布情况&…

Trae:国内首款AI原生IDE,编程效率大提升

今年一月&#xff0c;在新闻上看到字节跳动面向海外市场推出了一款名为Trae的AI集成开发环境&#xff08;IDE&#xff09;。起初&#xff0c;我并未给予过多关注&#xff0c;因为市面上已有不少IDE集成了AI插件&#xff0c;功能也非常全面&#xff0c;而字节跳动自家的MarsCode…

实训任务1.3 使用eNSP搭建基础网络

目录 1.【实训目标】 2.【实训内容】 1.【实训目标】 1.掌握eNSP仿真软件的基本操作方法。 2.掌握使用eNSP仿真软件搭建简单的端到端网络的方法。 【实训环境】 1.硬件环境&#xff1a;每人一台配置网卡的计算机。 2.软件环境&#xff1a;华为eNSP仿真软件。 2.【实训内…