百万数据SQL优化技巧,看这一篇就够了(实操+详细总结)

news2024/11/25 7:06:27

前言:这次准备了100W的数据进行SQL性能测试,数据库采用的是MySQL,总共介绍了常见的15种SQL优化方式,每一种优化方式都进行了实打实的测试,逐行讲解,通俗易懂!

目录

一、准备数据

1、创建表结构

2、创建存储过程 

二、索引介绍

1、类型介绍

2、建立索引

3、建立复合索引

4、查看所有建立的索引

5、删除索引

三、EXPLAIN分析参数说明

四、SQL优化案例

1、避免使用SELECT *

2、慎用UNION关键字

3、小表驱动大表 

4、避免使用or条件(有争议)

5、LIKE语句优化

6、字符串字段优化

7、最左匹配原则(重要)

8、COUNT查询数据是否存在优化 

9、LIMIT关键字优化 

10、提升GROUP BY的效率

11、避免使用!=或<>

12、避免NULL值判断

13、避免函数运算

14、JOIN的表中使用索引字段

15、用EXISTS代替IN

五、总结


一、准备数据

提前准备一张学生表数据和一张特殊学生表数据,用于后面的测试用。

1、创建表结构

创建一个学生表:

CREATE TABLE student (
  id int(11) unsigned NOT NULL AUTO_INCREMENT,
  name varchar(50) DEFAULT NULL,
  age tinyint(4) DEFAULT NULL,
  id_card varchar(20) DEFAULT NULL,
  sex tinyint(1) DEFAULT '0', 
  address varchar(100) DEFAULT NULL,
  phone varchar(20) DEFAULT NULL, 
  create_time timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  remark varchar(200) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

再创建一个特殊学生表:

CREATE TABLE special_student (
  id int(11) unsigned NOT NULL AUTO_INCREMENT,
  stu_id int(11) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、创建存储过程 

在学生表中插入100w条数据,手动开启和提交事务,每插入1w条记录后,手动COMMIT一次事务,最后再COMMIT一次以提交剩下的记录,这样可以让插入速度更快,因为不需要为每条记录都 COMMIT,从而降低 IO 次数。

CREATE PROCEDURE insert_student_data()
BEGIN
  DECLARE i INT DEFAULT 0; 
  DECLARE done INT DEFAULT 0; 
  DECLARE continue HANDLER FOR NOT FOUND SET done = 1;
  START TRANSACTION;  
   WHILE i < 1000000 DO
     INSERT INTO student(name,age,id_card,sex,address,phone,remark)
     VALUES(CONCAT('姓名_',i), FLOOR(RAND()*100),
         FLOOR(RAND()*10000000000),FLOOR(RAND()*2),
         CONCAT('地址_',i), CONCAT('12937742',i),
         CONCAT('备注_',i));
     SET i = i + 1; 
     IF MOD(i,10000) = 0 THEN 
       COMMIT;
       START TRANSACTION;
     END IF;     
   END WHILE;    
   COMMIT;
END

执行学生表的存储过程:

CALL insert_student_data();

在特殊学生表中随机插入100条学生表中的id:

CREATE PROCEDURE insert_special_student()
BEGIN
  DECLARE i INT DEFAULT 0; 
  WHILE i < 100 DO
    INSERT INTO special_student (stu_id) VALUES (FLOOR(RAND()*1000000));  
    SET i = i + 1;   
  END WHILE;
END

执行特殊学生表的存储过程: 

CALL insert_special_student();

二、索引介绍

1、类型介绍

普通索引最基本的索引,没有任何限制
唯一索引与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值
主索引即主键索引,关键字PRIMARY
复合索引为了更多的提高MySQL效率可建立组合索引,遵循“最左前缀”原则
全文索引可用于MyISAM表,MySQL5.6之后也可用于innodb表,用于在一篇文章中,检索文本信息的, 针对较大的数据,生成全文索引很耗时和空间

2、建立索引

CREATE INDEX id_card_index ON student(id_card);

3、建立复合索引

CREATE INDEX name_address_phone_index ON student(name,address,phone);

4、查看所有建立的索引

SHOW INDEX FROM student;

5、删除索引

ALTER TABLE 表名 DROP INDEX 索引名称;

三、EXPLAIN分析参数说明

1、id:SELECT语句的编号。可以通过id来区别多条SELECT语句。

2、select_type:SELECT类型,主要有SIMPLE、PRIMARY、DERIVED等类型。

SIMPLE:简单的SELECT(不含子查询及UNION)。

PRIMARY:查询中最外层的SELECT。

DERIVED:包含的子查询中的SELECT。

3、table:显示这一行的数据是关于哪张表的。

4、partitions:匹配的分区信息。

5、type:显示连接使用了何种类型。

最好到最差的连接类型为 system > const > eq_reg > ref > range > index > ALL.

system

表只有一行记录(等于系统表)
const使用常量进行索引查询
eq_ref唯一索引扫描,通常使用主键约束
ref非唯一性索引扫描
range索引范围扫描
index全索引扫描
ALL全表扫描

6、possible_keys:显示可能应用在这张表中的索引。

7、key:实际使用的索引。

8、key_len:使用的索引的长度。

9、ref:显示索引的哪一列被使用。

10、rows:根据表统计信息及索引条件估算,查询返回的且接近的行数

11、filtered:显示了通过条件过滤出的行数的百分比估计值。

12、Extra:包含不适合在其他列展示但是需要展示的信息。

四、SQL优化案例

1、避免使用SELECT *

有的时候,我们为了图方便,会直接使用SELECT * 一次性查出表中所有的数据:

SELECT * FROM student

执行结果如图所示:

可以看到,执行时间花了2s左右,耗时很长!

在实际开发中,我们给页面展示的数据可能就只要2-3个字段,如果直接全部查出来了,岂不是白白浪费了字段,同时也损耗了性能,这是因为SELECT * 不会走覆盖索引,会出现大量的回表操作,从而导致SQL性能大幅度降低。

我们上面建立了联合索引,我们就可以只查询索引列,这样会大幅度提升查询效率,优化的SQL如下:

SELECT name,address,phone FROM student

执行结果如图所示:

这样执行的速度大大提高!

分析SQL:

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT name,address,phone FROM student

执行结果如图所示:

确实走了我们建立的复合索引。 

2、慎用UNION关键字

例如我们根据性别去查询所有学生的信息,虽然这种操作多此一举,直接SELECT *就好了,为了演示这2个关键字的详细区别,使用UNION关键字执行的SQL如下:

SELECT * FROM student WHERE sex = 0
UNION 
SELECT * FROM student WHERE sex = 1

执行结果如图所示: 

我滴妈,查了100w条足足整整等了32s左右,这个速度要是放到系统上,查个数据等到娃娃菜都凉了!

这是因为在使用UNION执行完SQL后,会帮我们获取所有数据并去掉重复的数据,性能的损耗就在这里,而UNION ALL和UNION相反,帮我们获取所有数据但会保留重复的数据。

我们改用UNION ALL关键字,优化的SQL如下:

SELECT * FROM student WHERE sex = 0
UNION ALL
SELECT * FROM student WHERE sex = 1

执行结果如图所示:

同样查询100w条数据,这边执行速度大大提高了,只用到了3s左右! 

3、小表驱动大表 

言简意赅,意思就是让小表查出来的数据去再查询大表当中的数据。比如我们想查询学生表当中特殊学生的信息,我们就可以使用以special_student这个小表去驱动student这个大表,SQL如下:

SELECT * FROM student WHERE id 
IN (SELECT stu_id FROM special_student)

执行结果如图所示:

只用了0.02s,速度很可观!因为IN关键字中的子查询语句,子查询语句的数据量很少,所以查询速度会很快!

4、避免使用or条件(有争议)

如果我们要查询指定的性别或者指定的身份证号码的学生,执行SQL如下:

SELECT * FROM student WHERE sex = 0 OR id_card = '7121877527789'

执行结果如图所示:

总共查询了近50w条数据,耗时1.4s左右,我们改用UNION ALL关键字查询:

SELECT * FROM student WHERE sex = 0 
UNION ALL 
SELECT * FROM student WHERE id_card = '7121877527789'

执行结果如图所示:

和上面查询的数据量一样,好事在1.7s左右,怎么会没什么区别呢?

分析SQL: 

使用EXPLAIN关键字分析一下使用OR关键字的这段SQL:

EXPLAIN SELECT * FROM student WHERE SEX = 0 OR id_card = '7121877527789'

执行结果如图所示: 

很明显,虽然可能会用到建立id_card的索引,正因为sex这个字段没有建立索引,还是走了一次全表扫描。

使用EXPLAIN关键字执行这段SQL:

EXPLAIN
SELECT * FROM student WHERE sex = 0 
UNION ALL 
SELECT * FROM student WHERE id_card = '7121877527789'

执行结果如图所示:

很明显条件是sex的走了全表,但是id_card走了索引,所以依旧还是走了一次全表扫描,所以网上说的关于UNION ALL代替OR的,我这边实测感觉还是存在争议的!

5、LIKE语句优化

平时我们日常开发用到的LIKE关键字进行模糊匹配会非常多,但是有的情况会使索引失效,导致查询效率变慢,例如:

只要身份证字段包含50就查出来,执行SQL如下:

SELECT * FROM student WHERE id_card like '%50%'

执行结果如图所示:

用了0.8s左右。

只要身份证号码以50结尾就查出来,执行SQL如下:

SELECT * FROM student WHERE id_card like '%50'

执行结果如图所示:

用了0.4s左右。

只要身份证号码以50开头的就查出来,执行SQL如下:

SELECT * FROM student WHERE id_card like '50%'

执行结果如图所示:

这次执行非常快,0.08s左右。

分析SQL:

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card like '%50%'

执行结果如图所示:

很明显走了全表扫描!

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card like '%50'

执行结果如图所示:

依旧走了全表扫描!

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card like '50%'

执行结果如图所示:

这次便走了索引!

6、字符串字段优化

查询指定的身份证号码的学生,如果我们平时疏忽了给身份证号码加上单引号,执行SQL如下:

SELECT * FROM student WHERE id_card = 5040198345

执行结果如图所示:

耗时0.4s左右。

给身份证号码加上单引号,优化的SQL如下:

SELECT * FROM student WHERE id_card = '5040198345'

执行结果如图所示:

耗时0.02s左右,这次明显快多了!

分析SQL:

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card = 5040198345

执行结果如图所示:

可能用到了id_card的索引,但是还是走了全表扫描!

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card = '5040198345'

执行结果如图所示: 

这边走了索引。 

7、最左匹配原则(重要)

上面我们按照name,address和phone这个顺序建立了复合索引,相当于建立了(name),(name、address)和(name、address、phone)三个索引,如果我们查询的where条件违背了建立的顺序,则复合索引就失效了,下面直接进行SQL分析:

分析SQL:

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE name = '姓名_4' and phone = '7121877527' and address = '地址_4'

执行结果如图:

为什么明明违背了最左匹配原则,依旧还是走了复合索引呢?可能是如下原因:

1、通过索引过滤性能足够好,所以还是选择利用索引。

2、联合索引中前几个字段过滤效果较好,所以仍然选择利用索引。

可能的执行计划大概是:

1、优先通过phone字段过滤,将要扫描的记录减少一部分。
2、然后通过address字段继续过滤,再减少一部分记录。
3、最后通过name字段过滤,已经剩下很少的记录需要扫描。
4、尽管违反了最左匹配,解释器可能认为仍然利用索引效率比较高。

所以总的来说,就是解释器会根据实际情况进行权衡,即使是违反最左匹配原则,也可能会选择利用索引。但这并不是一个良好的查询优化,最好还是严格遵守最左匹配原则。

以下是严格遵守最左匹配原则的SQL:

SELECT * FROM student WHERE name = '姓名_4' 
SELECT * FROM student WHERE name = '姓名_4' and address = '地址_4' 
SELECT * FROM student WHERE name = '姓名_4' and address = '地址_4' and phone = '7121877527' 

8、COUNT查询数据是否存在优化 

比如我想判断年龄为18岁的学生是否存在,我们往往会执行如下SQL:

SELECT COUNT(*) FROM student WHERE age = 18

执行结果如图所示:

耗时0.4s左右,虽然知道学生年龄18岁存在,但是没必要查询出这么多数量出来,我们只要知道是否存在即可!

不再使用COUNT,而是改用LIMIT 1,让数据库查询时遇到一条就返回,这样就不要再继续查找还有多少条了,优化的SQL如下:

SELECT 1 FROM student WHERE age = 18 LIMIT 1

执行结果如图所示:

耗时0.01s左右,很快就知道了。 

9、LIMIT关键字优化 

 平日开发工作中,我们对于分页的处理一般是这样的:

SELECT * FROM student LIMIT 999910,10

执行结果如图所示: 

耗时0.56s,但是因为我们的ID属于自增长,所以我们可以在此基础上进行一定的优化,优化的SQL如下: 

SELECT * FROM student WHERE ID >= 999910 LIMIT 10

执行结果如图所示:

仅仅用时0.02s,非常快!

10、提升GROUP BY的效率

我们平日写SQL需要多多少少会使用GROUP BY关键字,它主要的功能是去重和分组。 通常它会跟HAVING一起配合使用,表示分组后再根据一定的条件过滤数据,常规执行的SQL如下:

SELECT age,COUNT(1) FROM student GROUP BY age HAVING age > 18

执行结果如图所示:

耗时总计0.53s左右,不过还可以进行优化,我们可以在分组之前缩小筛选的范围,然后再进行分组,优化的SQL如下:

SELECT age,COUNT(1) FROM student where age > 18 GROUP BY age 

执行结果如图所示:

耗时0.51s左右,虽然不明显,也是一种不错的思路。

11、避免使用!=或<>

尽量避免使用!=或<>操作符,下面直接分析SQL:

SQL分析:

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card != '5031520645'

执行结果如图所示:

虽然我们给了id_card字段建立了索引,但还是走了全表扫描!

12、避免NULL值判断

为了确保没有NULL值,我们可以设定一个默认值,下面直接分析SQL:

SQL分析:

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card IS NOT NULL

执行结果如图所示:

依旧还是走了全表扫描。

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE id_card IS NULL

执行结果如图所示:

这样是走索引的!

13、避免函数运算

在日常SQL撰写中,在WHERE条件上多多少少会用到一些函数,例如截取字符串,执行SQL如下:

分析SQL: 

使用EXPLAIN关键字执行这段SQL:

EXPLAIN SELECT * FROM student WHERE SUBSTR(id_card,0,9)

执行结果如图所示: 

索引失效,走了全表扫描。 

14、JOIN的表中使用索引字段

如果日常开发中,使用JOIN关键字链接表后,使用的ON关键字进行条件链接时,如果条件没有索引,则会进行全表扫描,执行SQL如下:

EXPLAIN SELECT * FROM student a,special_student b WHERE a.id = b.stu_id

执行结果如图所示: 

正因为special_student表的stu_id没有建立索引,则导致了全表扫描!

为stu_id建立索引后,执行SQL如下:

CREATE INDEX stu_id_index ON special_student(stu_id);

EXPLAIN SELECT * FROM student a,special_student b WHERE a.id = b.stu_id

执行结果如图所示:  

两张表都走了索引。

15、用EXISTS代替IN

IN关键字适合于外表大而内表小的情况,EXISTS适合于外表小而内表大的情况,执行SQL如下:

SELECT * FROM special_student 
WHERE EXISTS 
( SELECT 1 FROM student WHERE special_student.stu_id = student.id)

运行结果如图所示:

执行效率在0.02s左右,这里special_student是小表,student是大表,速度非常快!

五、总结

以上就是目前我对SQL优化的一些个人理解和总结,如果遗漏,欢迎评论区补充说明!

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

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

相关文章

Windows环境下安装和配置python环境

Windows环境下安装和配置python环境 1.官网下载&#xff1a;https://www.python.org/downloads/release 2.安装&#xff1a;自定义路径即可无脑下一步 3.cmd打开控制台&#xff0c;输入python&#xff0c;如果页面切换成以下样子就说明安装成功了 4.运行python脚本【步骤3切入…

555、Vue 3 学习笔记 -【常用Composition API(四)】 2023.07.06

目录 一、setup的两个注意点1. setup执行的时机2. setup的参数 二、 计算属性与监视1. computed函数2. watch函数3. watchEffect函数 三、参考链接 一、setup的两个注意点 1. setup执行的时机 在beforeCreate之前执行一次&#xff0c;this是undefined 2. setup的参数 props…

GitLab名词介绍

GitLab名词介绍 分支&#xff1a;active、stale、default、protected IDEA中git面板&#xff1a;本地、远程、HEAD 合并时的选项&#xff1a;Delete、squash 查看Git常用操作 分支&#xff1a;active、stale、default、protected 在分支页面下&#xff0c;有active、stale…

k8s中kubectl陈述式/声明式资源管理

k8s陈述资源管理方法的说明 1.kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口 2.kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为 apiserver 能识别的信息&…

TongWeb8关于内存泄露提示: To prevent a memory leak

原因&#xff1a; 该问题与 https://blog.csdn.net/realwangpu/article/details/109510297 相同&#xff0c;TongWeb7, TongWeb8在卸载应用时&#xff0c;会尝试回收可能存在的内存泄露&#xff0c; 本质应该从应用方面解决。 解决办法&#xff1a; 若无法修改应用&#xff0c…

深度学习神经网络学习笔记-论文研读-transformer

摘要 优势序列转导模型基于复杂的循环或包括一个编码器和一个解码器的卷积神经网络。最好的表现良好的模型还通过attention 连接编码器和解码器机制。我们提出了一种新的简单的网络架构&#xff0c;Transformer&#xff0c; 完全基于注意力机制&#xff0c;省去了递归和卷积完…

【成都理工826】22年真题及解析

哈喽大家好&#xff0c;鉴于真题系列反馈很不错&#xff0c;我决定重启真题系列&#xff01;之前更新的22真题合集点击这里&#xff1a; 成都理工826信号与系统难度不是特别大&#xff0c;但是对计算的要求比较高。掌握好基础&#xff0c;计算细心是可以拿高分的。本套试题内容…

【我们一起60天准备考研算法面试(大全)-第四天 4/60(二叉搜索树与表达式树)】【每天40分钟,我们一起用60天准备 考研408-数据结构(笔试)】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

github搜索技巧笔记

一、了解 GitHub Watch按钮 Watch可以理解为关注的意思&#xff0c;默认情况下是Not watching&#xff0c;当选择Watch后&#xff0c;你会收到这个GitHub项目的所有动态。比如&#xff1a;有人发起pull request或者issue等。接收动态方式包括个人通知中心或者邮箱。 如果某个…

TypeScript - 函数(中)

目录 1、编写良好泛型函数的准则 1.1 向下推送类型参数 1.2 使用较少的类型参数 1.3 类型参数应出现两次 2、可选参数 3、回调中的可选参数 4、函数重载 5、重载签名和实现签名 6、写好重载 1、编写良好泛型函数的准则 编写泛型函数很有趣&#xff0c;并且很容易被类…

Kibana对索引库的操作(3)

这里我们主要是对索引库进行各种查询的操作,所以要提前准备一些数据 POST /leq/goods/3 {"title": "小米手机","images": "3.jpg","price": 4299,"stock": 200,"saleable": true,"subTitle":…

读发布!设计与部署稳定的分布式系统(第2版)笔记20_实例层之代码

1. 术语的定义 1.1. 服务 1.1.1. 指共同协作、以单元的形式对外提供功能的跨机器进程集合 1.1.2. 一个服务可以由多种可执行文件组成 1.1.3. 一个服务可能包含来自多个可执行文件的多个进程 1.1.4. 可能对外呈现单个IP地址&#xff0c;并在后台进行负载均衡 1.1.5. 可能有…

潇洒郎: bat文件与vbs文件, 执行命令行命令以及执行时无console, reg文件注册表

截图.bat start snippingtool 锁屏.bat rundll32.exe user32.dll,LockWorkStation redis.bat cd %~dp0 redis-server.exe redis.windows.conf vbs Set ws CreateObject("Wscript.Shell") ws.run "cmd /c C:/Python27/Scripts/ride.bat",vbhide 在上…

记录好项目D23

记录好项目 你好呀&#xff0c;这里是我专门记录一下从某些地方收集起来的项目&#xff0c;对项目修改&#xff0c;进行添砖加瓦&#xff0c;变成自己的闪亮项目。修修补补也可以成为毕设哦 本次的项目是个基于Springboot教务管理系统 一、系统介绍 这个项目是一个简单的教…

Slowhttptest----DoS攻击工具

Slowhttptest----DoS攻击工具 文章目录 slowhttptestcentos下安装slowhttptestUbuntu 20.04 LTS下安装slowhttptest使用 slowhttptest SlowHTTPTest 是依赖 HTTP 协议的慢速攻击 DoS 攻击工具。 工具的设计基本原理是服务器在请求完全接收后才会进行处理。 如果客户端的 HTT…

香港银行开个人账户应该选择哪个银行,附详细指南

香港现在陆续通关&#xff0c;开户是越来越方便&#xff0c;目前已经很多有账户需求的都过去开户了&#xff0c;那现在个人在香港银行开户的话可以开哪些银行呢&#xff1f;我列举了几个&#xff0c;可以参考下 汇丰个人户&#xff0c;当场开好拿卡使用 恒生个人户&#xff0…

商标注册 | 美国商标注册资料、流程、时间、方式一文详解

中国对外贸易市场中&#xff0c;美国是当仁不让的重要出口市场&#xff0c;这成为众多国内企业产品出海的先选目的地。产品出口也会涉及到一系列知识产权问题&#xff0c;而这个问题之一就是美国商标的注册。 美国的商标保护非常完善&#xff0c;它不仅可以阻止侵权商品进入美…

【ts】变量的类型注解

ts使用类型注解的好处&#xff1a;使用类型注解&#xff0c;可以使代码更加清晰和易于理解&#xff0c;在处理复杂的数据解构的时候&#xff0c;提高代码的可读性和可维护性。 在vue3中&#xff0c;类型注解是可选的&#xff0c;可用可不用&#xff0c;如果不用&#xff0c;vue…

机器学习 day22(ReLU激活函数,激活函数的种类,如何选择激活函数)

ReLU激活函数 当问题的结果是二元的&#xff0c;则a的范围是&#xff08;0&#xff0c;1&#xff09;激活函数g(z)可以用sigmoid激活函数。如果问题的结果是多元的&#xff0c;如让a的范围取(0&#xff0c;∞)&#xff0c;激活函数g(z)可以选用ReLU激活函数&#xff0c;他在z…

深入理解预训练(pre-learning)、微调(fine-tuning)、迁移学习(transfer learning)三者的联系与区别

1. 什么是预训练和微调 你需要搭建一个网络模型来完成一个特定的图像分类的任务。首先&#xff0c;你需要随机初始化参数&#xff0c;然后开始训练网络&#xff0c;不断调整参数&#xff0c;直到网络的损失越来越小。在训练的过程中&#xff0c;一开始初始化的参数会不断变化。…