数据库--进阶版-11--SQL优化
创始人
2025-05-31 15:42:50

1.插入数据

·insert优化:

例如要插入下面这些

insert into tb_test values(1,'tom');

insert into tb_test values(2,'cat');

insert into tb_test values(3,'jerry');

我们可以通过以下几个方面进行操作:

>批量插入(如果一次性要插入多条数据可以通过一条insert语句来完成)

像上面这样每次insert都要与数据库进行连接进行网络传输,这样性能相对是比较低的,所以可以考虑用批量插入。

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

不过不能超过一千条,如果要一次插入一万条数据怎么办?可以可以分割为多条insert语句插入嘛

>手动提交事务

MySQL中事务提交方式默认是自动的,也就是说,当你执行完一条SQL语句后,它事务就提交了,再次执行一条insert,执行之前开启事务,执行完毕又关闭事务,这时候就涉及事务的频繁开启与提交,所以我们建议手动提交事务。

在insert之前开启事务,然后执行完多条SQL语句后再统一提交事务

例:

start transaction;

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

insert into tb_test values(4,'tom1'),(5,'cat1'),(6,'jerry1');

insert into tb_test values(7,'tom2'),(8,'cat2'),(9,'jerry2');

commit;

>主键顺序插入

主键插入要么乱序插入要么顺序插入,建议主键顺序插入,因为顺序插入性能高于乱序插入。

·大批量插入数据

如果一次性需要插入大批量数据,比如要一次性将一百万的数据加载进表结构中,使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入。

需要做3步操作:

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

在执行load指令时我们也建议按照主键顺序插入,主键顺序插入性能高于乱序插入。

2.主键优化

·数据组织方式:

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

回顾之前的逻辑存储结构:

表空间(里面存储一个个段)-->段(里面存储一个个区)-->区(大小固定为1M,里面存储一个个页)-->页(大小固定为16K,里面存储一个个行)-->行(当中存放的就是具体的字段值)

页是innoDB磁盘管理的最小单元,一个页大小默认为16K,也就意味着一个区当中可以包含64个页。接下来我们看一下当我们往数据库表结构中插入数据的时候它的流程是什么样的。

主要理解好页分裂和页合并的原理是什么

·页分裂

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

可知如果主键乱序插入即可能会导致页分裂现象

·页合并

当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记为删除并且它的空间变得允许被其它记录声明使用。当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),innoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。

·主键设计原则:

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

我们知道二级索引是可以有很多个嘛,而二级索引叶子节点存储的就是主键,如果你主键长度太长,那么就会占用大量的磁盘空间,而且在搜索的时候会耗费大量的磁盘io

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

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

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

3.order by优化

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

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

所以尽量优化为using index。

为什么会出现using filesort呢?因为没有用到索引,通过创建索引再执行就可以优化为using index,出现using index就说明我们的排序效率比较高,因为它直接通过索引给我们返回了有序数据。

例:

总结:

>根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则

>尽量使用覆盖索引

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

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

4. group by 优化

分组操作的时候,我们主要研究的就是索引对分组操作的影响。

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

>分组操作时,索引的使用也需要满足最左前缀法则的

5.limit优化

对于limit来说,对于大数据量的情况下你进行分页查询,越往后它的效率越低耗时越长。所以在大数据量的情况下我们就需要对limit分页操作进行优化。

一个常见又非常头疼的问题是limit2000000,10,此时需要MySQL排序前2000010记录,仅仅返回2000000-2000010的记录,其它记录丢弃,查询排序的代价非常大。

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

6.count优化

>MyISAM引擎把一个表的总行数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率很高,不过前提是查询时后面没有where条件哈;

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

优化思路:自己计数

·count的几种用法:

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

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

接下来就学习这几种用法以及它的性能

>count(主键)

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

>count(字段)

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

有not null约束:InnoDB引擎会遍历整张表,把每一行的主键id值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加。

>count(1)

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

>count(*)

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

哪哪个效率高呢?

就看它取不取值,你看count(*)count(1)都不取值,count(主键)取主键值,count(字段)看情况。

所以按照效率排序的话,count(字段)

7.update优化(避免行锁升级为表锁)

之前我们学InnoDB的时候提到了它的三大特性:事务,外键,行级锁。也就是说在InnoDB引擎中我们当前默认的事务隔离级别是行锁。

进行update语句的时候,如果后面条件没有索引,那么行锁就会升级为表锁。

如比如某表id有索引,name没有建立索引

然后你还update student set no=‘200103080020’ where name='陈小画';就会引起行锁升级为表锁

所以进行update语句的时候,我们一定要根据索引字段进行更新,否则就会造成行锁升级为表锁,就会锁住整张表,那一旦锁表了,我们的并发性能就会降低。

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

相关内容

热门资讯

【实验报告】实验一 图像的... 实验目的熟悉Matlab图像运算的基础——矩阵运算;熟悉图像矩阵的显示方法࿰...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
大模型落地比趋势更重要,NLP... 全球很多人都开始相信,以ChatGPT为代表的大模型,将带来一场NLP领...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
kuernetes 资源对象分... 文章目录1. pod 状态1.1 容器启动错误类型1.2 ImagePullBackOff 错误1....
STM32实战项目-数码管 程序实现功能: 1、上电后,数码管间隔50ms计数; 2、...
TM1638和TM1639差异... TM1638和TM1639差异说明 ✨本文不涉及具体的单片机代码驱动内容,值针对芯...
Qt+MySql开发笔记:Qt... 若该文为原创文章,转载请注明原文出处 本文章博客地址:https://h...
Java内存模型中的happe... 第29讲 | Java内存模型中的happen-before是什么? Java 语言...
《扬帆优配》算力概念股大爆发,... 3月22日,9股封单金额超亿元,工业富联、鸿博股份、鹏鼎控股分别为3.0...
CF1763D Valid B... CF1763D Valid Bitonic Permutations 题目大意 拱形排列࿰...
SQL语法 DDL、DML、D... 文章目录1 SQL通用语法2 SQL分类3 DDL 数据定义语言3.1 数据库操作3.2 表操作3....
文心一言 VS ChatGPT... 3月16号,百度正式发布了『文心一言』,这是国内公司第一次发布类Chat...
CentOS8提高篇5:磁盘分...        首先需要在虚拟机中模拟添加一块新的硬盘设备,然后进行分区、格式化、挂载等...
Linux防火墙——SNAT、... 目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条...
部署+使用集群的算力跑CPU密... 我先在开头做一个总结,表达我最终要做的事情和最终环境是如何的,然后我会一...
Uploadifive 批量文... Uploadifive 批量文件上传_uploadifive 多个上传按钮_asing1elife的...
C++入门语法基础 文章目录:1. 什么是C++2. 命名空间2.1 域的概念2.2 命名...
2023年全国DAMA-CDG... DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义...
php实现助记词转TRX,ET... TRX助记词转地址网上都是Java,js或其他语言开发的示例,一个简单的...
【分割数据集操作集锦】毕设记录 1. 按要求将CSV文件转成json文件 有时候一些网络模型的源码会有data.json这样的文件里...
Postman接口测试之断言 如果你看文字部分还是不太理解的话,可以看看这个视频,详细介绍postma...
前端学习第三阶段-第4章 jQ... 4-1 jQuery介绍及常用API导读 01-jQuery入门导读 02-JavaScri...
4、linux初级——Linu... 目录 一、用CRT连接开发板 1、安装CRT调试工具 2、连接开发板 3、开机后ctrl+c...
Urban Radiance ... Urban Radiance Fields:城市辐射场 摘要:这项工作的目标是根据扫描...
天干地支(Java) 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:...
SpringBoot雪花ID长... Long类型精度丢失 最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数...
对JSP文件的理解 JSP是java程序。(JSP本质还是一个Servlet) JSP是&#...
【03173】2021年4月高... 一、单向填空题1、大量应用软件开发工具,开始于A、20世纪70年代B、20世纪 80年...
LeetCode5.最长回文子... 目录题目链接题目分析解题思路暴力中心向两边拓展搜索 题目链接 链接 题目分析 简单来说࿰...