MySQL篇(SQL优化)(持续更新迭代)

目录

一、插入数据:Insert

1. 优化方案一:批量插入数据

2. 优化方案二:手动控制事务

3. 优化方案三:主键顺序插入,性能要高于乱序插入

4. 大批量插入数据

5. 案例

5.1. 创建表结构

5.2. 设置参数

5.3. load加载数据

二、主键优化

1. 数据组织方式

2. 页分裂

2.1. 简介

2.2. 主键顺序插入效果

2.3. 主键乱序插入效果

3. 页合并

4. 索引设计原则

三、order by 优化

1. 简介

2. 测试

2.1. 数据准备

2.2. 执行排序SQL

2.3. 创建索引

2.4. 创建索引后,根据age, phone进行升序排序

2.5. 创建索引后,根据age, phone进行降序排序

2.6. 根据phone,age进行升序排序,phone在前,age在后

2.7. 根据age, phone进行降序一个升序,一个降序

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

2.9. 然后再次执行如下SQL

3. order by 优化原则

4. MySQL支持降序索引

四、groub by 优化

五、limit 优化

六、count优化

1. 简介

2. count用法

七、update优化


一、插入数据:Insert

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

insert into tb_test values(1,'tom');insert into tb_test values(2,'cat');insert into tb_test values(3,'jerry');.....

1. 优化方案一:批量插入数据

Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');

2. 优化方案二:手动控制事务

start transaction;insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');commit;

3. 优化方案三:主键顺序插入,性能要高于乱序插入

主键乱序插入 : 8 1 9 21 88 2 4 15 89 5 7 3 主键顺序插入 : 1 2 3 4 5 7 8 9 15 21 88 89

4. 大批量插入数据

如果一次性需要插入大批量数据(比如: 几百万的记录),使用insert语句插入性能较低,

此时可以使用MySQL数据库提供的load指令进行插入。

操作如下:

可以执行如下指令,将数据脚本文件中的数据加载到表结构中:

-- 客户端连接服务端时,加上参数 -–local-infilemysql –-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' ; 

5. 案例

5.1. 创建表结构

CREATE TABLE tb_user (id INT(11) NOT NULL AUTO_INCREMENT,username VARCHAR(50) NOT NULL,password VARCHAR(50) NOT NULL,name VARCHAR(20) NOT NULL,birthday DATE DEFAULT NULL,sex CHAR(1) DEFAULT NULL,PRIMARY KEY (id),UNIQUE KEY unique_user_username (username)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

5.2. 设置参数

-- 客户端连接服务端时,加上参数 -–local-infilemysql –-local-infile -u root -p-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关set global local_infile = 1;

5.3. load加载数据

load data local infile '/root/load_user_100w_sort.sql' into table tb_userfields terminated by ',' lines terminated by '\n' ; 

我们看到,插入100w的记录,17s就完成了,性能很好。

在load时,主键顺序插入性能高于乱序插入

二、主键优化

前面,我们提到,主键顺序插入的性能是要高于乱序插入的。

接下来就介绍一下具体的原因,然后再分析一下主键又该如何设计。

1. 数据组织方式

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

(index organized table IOT)

行数据,都是存储在聚集索引的叶子节点上的。

在InnoDB引擎中,数据行是记录在逻辑结构 page 页中的,而每一个页的大小是固定的,默认16K。

那也就意味着, 一个页中所存储的行也是有限的,如果插入的数据行row在该页存储不下,

将会存储到下一个页中,页与页之间会通过指针连接。

2. 页分裂

2.1. 简介

页可以为空,也可以填充一半,也可以填充100%。

每个页包含了2-N行数据(如果一行数据过大,会行溢出),根据主键排列。

2.2. 主键顺序插入效果

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

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

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

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

2.3. 主键乱序插入效果

① 加入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:合并页的阈值,可以自己设置,在创建表或者创建索引时指定。

4. 索引设计原则

① 满足业务需求的情况下,尽量降低主键的长度。

② 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。

③ 尽量不要使用UUID做主键或者是其他自然主键,如身份证号。

④ 业务操作时,避免对主键的修改。

三、order by 优化

1. 简介

MySQL的排序,有两种方式

第一种方式:Using filesort

通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,

所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。

第二种方式:Using index

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

对于以上的两种排序方式,Using index的性能高,而Using filesort的性能低,

我们在优化排序操作时,尽量要优化为 Using index。

2. 测试

接下来,我们来做一个测试:

2.1. 数据准备

把之前测试时,为tb_user表所建立的部分索引直接删除掉

drop index idx_user_phone on tb_user;drop index idx_user_phone_name on tb_user;drop index idx_user_name on tb_user;

2.2. 执行排序SQL

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, 排序性能较低。

2.3. 创建索引

-- 创建索引
create index idx_user_age_phone_aa on tb_user(age,phone);

2.4. 创建索引后,根据age, phone进行升序排序

explain select id,age,phone from tb_user order by age;

explain select id,age,phone from tb_user order by age, phone;

建立索引之后,再次进行排序查询,就由原来的Using filesort, 变为了 Using index,性能就是比较高的了。

2.5. 创建索引后,根据age, phone进行降序排序

explain select id,age,phone from tb_user order by age desc, phone desc ;

也出现 Using index, 但是此时Extra中出现了 Backward index scan,这个代表反向扫描索引,

因为在MySQL中我们创建的索引,默认索引的叶子节点是从小到大排序的,而此时我们查询排序时,是从大到

小,所以,在扫描时,就是反向扫描,就会出现 Backward index scan。

在MySQL8版本中,支持降序索引,我们也可以创建降序索引。

2.6. 根据phone,age进行升序排序,phone在前,age在后

explain select id,age,phone from tb_user order by phone, age ;

排序时,也需要满足最左前缀法则,否则也会出现 filesort。

因为在创建索引的时候, age是第一个字段,phone是第二个字段,

所以排序时,也就该按照这个顺序来,否则就会出现 Using filesort。

2.7. 根据age, phone进行降序一个升序,一个降序

explain select id,age,phone from tb_user order by age asc, phone desc ;

因为创建索引时,如果未指定顺序,默认都是按照升序排序的,而查询时,一个升序,一个降序,此时就会出现

Using filesort。

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

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

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

2.9. 然后再次执行如下SQL

explain select id,age,phone from tb_user order by age asc , phone desc ;

升序/降序联合索引结构图示:

3. order by 优化原则

由上述的测试,我们得出order by优化原则

  1. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则
  2. 尽量使用覆盖索引
  3. 多字段排序, 一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)
  4. 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小 sort_buffer_size(默认256k)

4. MySQL支持降序索引

在MySQL中我们创建的索引,默认索引的叶子节点是从小到大排序的,如果我们查询排序时,是从大到小,

在扫描时,就是反向扫描,就会出现 Backward index scan。

因为创建索引时,如果未指定顺序,默认都是按照升序排序的,而查询时,一个升序,一个降序,此时就会出现Using filesort

在MySQL8版本中,支持降序索引,我们也可以创建降序索引

比如:解决上述的问题,我们可以创建一个索引,假设联合索引中 age 升序排序,phone 倒序排序。

创建联合索引(age 升序排序,phone 倒序排序),这样就可以提升我们排序查询的效率

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

四、groub by 优化

分组操作,我们主要来看看索引对于分组操作的影响。

首先我们先将 tb_user 表的索引全部删除掉 。

drop index idx_user_pro_age_sta on tb_user; drop index idx_email_5 on tb_user; drop index idx_user_age_phone_aa on tb_user; drop index idx_user_age_phone_ad on tb_user;

接下来,在没有索引的情况下,执行如下SQL,查询执行计划:

explain select profession , count(*) from tb_user group by profession ;

然后,我们在针对于 profession , age, status 创建一个联合索引。

create index idx_user_pro_age_sta on tb_user(profession, age , status);

紧接着,再执行前面相同的SQL查看执行计划。

explain select profession , count(*) from tb_user group by profession ;

再执行如下的分组查询SQL,查看执行计划:

我们发现,如果仅仅根据age分组,就会出现 Using temporary ;

而如果是 根据 profession,age两个字段同时分组,则不会出现 Using temporary。

原因是因为对于分组操作,在联合索引中,也是符合最左前缀法则的。

所以,在分组操作中,我们需要通过以下两点进行优化,以提升性能:

  • 在分组操作时,可以通过索引来提高效率。
  • 分组操作时,索引的使用也是满足最左前缀法则的。

五、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;

六、count优化

1. 简介

select count(*) from tb_user ;

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

  • MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高;

但是如果是带条件的count,MyISAM也慢。

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

数。如果说要大幅度提升InnoDB表的count效率,主要的优化思路:自己计数(可以借助于redis这样的数 据

库进行,但是如果是带条件的count又比较麻烦了)。

2. count用法

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

1,否则不加,最后返回累计值。

用法:count(*)、count(主键)、count(字段)、count(数字)

count用 法

含义

count(主键)

·InnoDB 引擎会遍历整张表,把每一行的 主键id 值都取出来,返回给服务层。 服务层拿到主键后,直接按行进行累加(主键不可能为null)

count(字段)

没有not null 约束 : InnoDB 引擎会遍历整张表把每一行的字段值都取出 来,返回给服务层,服务层判断是否为null,不为null,计数累加。 有not null 约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返 回给服务层,直接按行进行累加。

count(数字)

InnoDB 引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1”进去,直接按行进行累加。

count(*)

InnoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接 按行进行累加。

按照效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*),所以尽量使用 count( * )

七、update优化

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

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

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

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

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

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

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

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

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

相关文章

IDAE中Quarkus框架(3.13版本)开发、调试、部署、打包等

code-with-quarkus code-with-quarkus 是使用官网生成的demo项目 这个项目使用Quarkus&#xff08;使用3.13.0版本&#xff0c;该版本支持JDK21&#xff09;&#xff0c;超音速亚原子Java框架。官网地址: https://quarkus.io/. 环境要求 OS: Windows 10.0 jdk 11 maven 3.9…

单元测试、集成测试、系统测试有什么不同?

单元测试、集成测试和系统测试是软件测试开发中不可或缺的部分。 单元测试&#xff1a; 范围&#xff1a;单元测试是对软件中最小的可测试单元的测试&#xff0c;通常是函数、方法或类。 目的&#xff1a;它的目标是验证每个单独的单元是否按照预期工作&#xff0c;以增加代码…

数据转换器——佛朗哥Chater 1

【注:本文基于《数据转换器》一书进行学习、总结编撰,适合新手小白进行学习】 目录 1.1 理想的数据转换器 1.2 采样 1.2.1 欠采样 1.2.2 采样时间的抖动(A/D转换的第一个精度限制) 1.3 幅度的量化 1.3.1 量化噪声(基本限制) 1.3.2 量化噪声的性质 1.4 KT/C噪声(…

Qt (19)【Qt 线程安全 | 互斥锁QMutex QMutexLocker | 条件变量 | 信号量】

阅读导航 引言一、互斥锁1. QMutex&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;使用示例基本需求⭕thread.h⭕thread.cpp⭕widget.h⭕widget.cpp 2. QMutexLocker&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;使用示例 3. QReadWriteLocker、QR…

【Linux】简易日志系统

目录 一、概念 二、可变参数 三、日志系统 一、概念 一个正在运行的程序或系统就像一个哑巴&#xff0c;一旦开始运行我们很难知晓其内部的运行状态。 但有时在程序运行过程中&#xff0c;我们想知道其内部不同时刻的运行结果如何&#xff0c;这时一个日志系统可以有效的帮…

软考无损连接判断

如何判断是否为无损连接&#xff0c;要看能否还原回最开始的关系模式 最开始的关系模式 U{A&#xff0c;B&#xff0c;C} 函数连接 F{A -> B}&#xff0c;这个函数连接的意思就是A可以推导出B 首先从P1开始判断&#xff0c;{ AB&#xff0c;BC } C不能通过函数依赖推导出来…

数据结构之线性表——LeetCode:328. 奇偶链表,86. 分隔链表,24. 两两交换链表中的节点

328. 奇偶链表 题目描述 328. 奇偶链表 给定单链表的头节点 head &#xff0c;将所有索引为奇数的节点和索引为偶数的节点分别组合在一起&#xff0c;然后返回重新排序的列表。 第一个节点的索引被认为是 奇数 &#xff0c; 第二个节点的索引为 偶数 &#xff0c;以此类推。…

头条|司法部公法局局长访谈:推进高水平公立鉴定机构建设!加快推进司法鉴定立法!

主持人&#xff1a;大家好&#xff0c;我是司法部AI主播司政轩。为切实做好党的二十届三中全会精神学习宣传贯彻&#xff0c;积极反映司法部及地方司法行政机关学习全会精神的体会收获和贯彻落实举措&#xff0c;我们推出了“学习宣传贯彻党的二十届三中全会精神--司法行政微访…

Elasticsearch 检索优化:停用词的应用

Elasticsearch 检索优化&#xff1a;停用词的应用 场景描述 目前在 Elasticsearch 集群中存储约 1.5 亿篇文章数据&#xff0c;随着数据量的增加&#xff0c;检索性能问题逐渐显现。在列表检索和聚合操作中&#xff0c;CPU 消耗飙升至 100%&#xff0c;并且检索耗时较长&…

私域电商:自主发展新路径与创新模式融合

摘要&#xff1a;本文深入探讨了私域电商相较于传统电商在自主权方面的优势&#xff0c;并结合 AI 智能名片、链动 21 模式以及商城小程序等创新元素&#xff0c;阐述了私域电商如何为商家提供更大的发展空间和自主权&#xff0c;以及这些创新模式在私域电商中的应用价值&#…

口碑最好的头戴式耳机是哪些?高品质头戴式耳机对比测评揭晓

头戴式耳机以其出色的音质表现和舒适的佩戴体验&#xff0c;成为了音乐爱好者和日常通勤用户的热门选择。而在众多品牌和型号中&#xff0c;口碑最好的头戴式耳机是哪些&#xff1f;面对市场上丰富的选择&#xff0c;找到一款音质优良、佩戴舒适且性价比高的耳机并不容易。今天…

ESP8266+DHT11+Python制作一个物联网温湿度传感器

ESP8266是一款低功耗、高集成度的Wi-Fi SOC&#xff08;System on Chip&#xff0c;系统级芯片&#xff09;&#xff0c;这款芯片专为物联网&#xff08;IoT&#xff09;应用而设计&#xff0c;常见开发ESP8266的环境可以使用Arduino或者ESP8266 RTOS SDK、NodeMCU&#xff0c;…

【JavaScript】数据结构之链表(双指针、滑动窗口)

什么是链表&#xff1f; 多个元素存储的列表链表中的元素在内存中不是顺序存储的&#xff0c;而是通过“next”指针联系在一起的&#xff0c;这个“next”可以自定义。JS中的原型链原理就是链表结构&#xff0c;是通过__proto__指针联系在一起的。 双指针形式 对撞指针&am…

你还在为试衣间排队烦恼吗?AI魔法绘,让虚拟试衣触手可及!

我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 大家好&#xff01;今天我要跟大家聊聊一个超级有趣又实用的新…

施耐德EcoStruxure Machine SCADA Expert(EMSE)报警记录进阶(十六)

针对某些特殊行业&#xff08;诸如医药行业&#xff09;的设备生产需要符合GMP相关规定&#xff0c;这就导致需要数据溯源。 EMSE可以通过与sql的连接实现报警历史记录的永久存储。 1.EMSE打开相关配置 2.sql创建表单 用于报警历史数据的存储容器 3.EMSE内选择sql表单 4.现在…

mistune,一个神奇的 Python 库!

大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - mistune。 Github地址&#xff1a;https://github.com/lepture/mistune Markdown 是一种轻量级的标记语言&#xff0c;以其简洁的语法和可读性广泛应用于文档编写、博客发布和在线内容管理系统中。Python 作为一门灵活…

【ESP32】ESP-IDF开发 | UART通用异步收发传输器+串口收发例程

1. 简介 UART可以说是开发者使用得最多的外设之一了&#xff0c;打印log几乎都是使用串口来实现的。UART是一种异步全双工的通信方式&#xff0c;异步传输的特性使得它仅需2根线就可以完成全双工的传输&#xff0c;但这也要求发送端和接收端的速率、停止位、奇偶校验位等都要相…

分布式计算技术是什么?在数据集成值得作用?

数据是现代科技技术的基础&#xff0c;面对爆炸性数据的增长&#xff0c;要求计算能力要求更高、数据整合和处理更有效&#xff0c;如何应对数据集成带来的挑战&#xff1f;本文将探讨分布式计算技术在数据集成中的优化作用。 一 分布式计算技术。 定义&#xff1a;分布式计算…

笔记:将WPF中可视化元素(Visual)保存为图像,如PNG,JPEG或BMP的方法简介

一、目的&#xff1a;将WPF中可视化元素&#xff08;Visual&#xff09;保存为图像&#xff0c;如PNG,JPEG或BMP的方法简介 BitmapEncoder 是 WPF 中用于将图像数据编码为特定格式的基类。它提供了将 BitmapSource 对象保存为各种图像格式&#xff08;如 PNG、JPEG、BMP 等&…

Android Choreographer 监控应用 FPS

Choreographer 是 Android 提供的一个强大的工具类&#xff0c;用于协调动画、绘制和视图更新的时间。它的主要作用是协调应用的绘制过程&#xff0c;以确保流畅的用户体验。Choreographer 也可以帮助我们获取帧时间信息&#xff0c;从而为性能监测和优化提供重要的数据支持。 …