当前位置: 首页 > news >正文

SQL优化案例教程0基础(小白必看)

前提准备:本案例准备了100W的数据进行SQL性能测试,数据库采用的是MySQL,

总共介绍了常见的14种SQL优化方式,每一种优化方式都进行了实打实的测试,

         逐行讲解,通俗易懂!

一、前提准备

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

1.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;

1.2  创建存储过程 

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

CREATE PROCEDURE insert_student_data()
BEGINDECLARE i INT DEFAULT 0; DECLARE done INT DEFAULT 0; DECLARE continue HANDLER FOR NOT FOUND SET done = 1;START TRANSACTION;  WHILE i < 1000000 DOINSERT 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()
BEGINDECLARE i INT DEFAULT 0; WHILE i < 100 DOINSERT INTO special_student (stu_id) VALUES (FLOOR(RAND()*1000000));  SET i = i + 1;   END WHILE;
END

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

CALL insert_special_student();

二、SQL优化案例详细介绍

2.1  返回必要的行

如果数量较大,可以使用 LIMIT 子句来限制返回的行数

select id,name from student limit 10

2.2  limit 优化

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

SELECT * FROM student LIMIT 900000,10

执行结果如图所示: 

耗时0.56s。当id为自增的情况下可以进行优化,优化的SQL如下: 

SELECT * FROM student WHERE ID >= 900000 LIMIT 10

优化后执行结果如图所示:

耗时0.02s,速度提升很多!

2.3  返回必要的列,避免使用SELECT *

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

SELECT * FROM student

执行结果如图所示:

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

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

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

SELECT name,address,phone FROM student

优化后执行结果如图所示:

耗时0.780s,速度提升很多!

2.4  or连接的条件(注意)

当使用OR操作符将多个条件组合在一起时,如果其中一个条件的列没有索引,那么涉及的索引不会被用到。

为了解决这个问题,可以考虑以下方案:

  • 确保所有涉及的条件列都有适当的索引,以提高查询性能。
  • 对于大型表,可以考虑重构查询,将OR操作符拆分成多个独立的查询,并使用UNION或UNION ALL来合并结果。这样可以确保每个子查询都能够使用适当的索引,并避免OR操作符导致的索引失效问题。

2.5  避免使用or条件,使用UNION或UNION ALL替代(有争议)

如果我们要查询指定的性别或者指定的身份证号码的学生,执行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'

改用后执行结果如图所示:

速度没有提升,反而慢了,故有争议

分析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的,我这边实测感觉还是存在争议的!

2.6  非必要情况下,慎用UNION关键字,使用UNION ALL替代

例如我们根据性别去查询所有学生的信息,虽然这种操作多此一举,直接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左右! 

速度提升很多!

2.7  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%'

执行结果如图所示:

这次便走了索引!速度快很多

2.8  尽量避免使用!=,导致索引失效

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

SQL分析:

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

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

执行结果如图所示:

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

2.9  尽量避免使用NULL值,IS NOT NULL会导致索引失效,IS 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

执行结果如图所示:

这样是走索引的!

2.10  使用小表驱动大表 ,避免大表驱动小表

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

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

执行结果如图所示:

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

2.11  避免字符串不加引号,导致索引失效

如果在查询条件或创建索引时字符串没有加上引号,会导致索引失效。

查询指定的身份证号码的学生,如果我们平时疏忽了给身份证号码加上单引号,执行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'

执行结果如图所示: 

加上引号,走了索引,速度快了很多!

2.12  避免对索引列上字段操作,导致索引失效

为了避免索引失效的问题,应该尽量避免在查询条件或者索引创建时对索引列进行运算。如果确实需要使用运算,可以考虑以下解决方案:

  • 对索引列进行逆转运算:如果运算是可逆的,可以通过将运算应用到查询参数上,而不是索引列上来维持索引的有效性。
  • 使用函数索引:某些数据库管理系统提供了函数索引的功能,可以根据特定的函数操作创建索引,以满足特定的查询需求。

2.13  遵循最左匹配原则(重要)

上面我们按照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' 

2.14  提升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左右,虽然不明显,也是一种不错的思路。

相关文章:

SQL优化案例教程0基础(小白必看)

前提准备&#xff1a;本案例准备了100W的数据进行SQL性能测试&#xff0c;数据库采用的是MySQL&#xff0c; 总共介绍了常见的14种SQL优化方式&#xff0c;每一种优化方式都进行了实打实的测试&#xff0c; 逐行讲解&#xff0c;通俗易懂&#xff01; 一、前提准备 提前准备一…...

webpack(一)模块化

模块化演变过程 阶段一&#xff1a;基于文件的划分模块方式 概念&#xff1a;将每个功能和相关数据状态分别放在单独的文件里 约定每一个文件就是一个单独的模块&#xff0c;使用每个模块&#xff0c;直接调用这个模块的成员 缺点&#xff1a;所有的成员都可以在模块外被访问和…...

基于Java+SpringBoot+Vue前后端分离人力资源管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…...

安装配置mariadb

记录下安装配置mariadb的经历。 环境&#xff1a;ubuntu22 一、apt在线安装 apt代理配置 APT是Ubuntu系统中用于安装和升级软件包的工具&#xff0c;如果本地没有可用的软件包&#xff0c;APT将会连接到远程软件包服务器下载软件包。在某些情况下&#xff0c;用户需要将APT的…...

Ant Design Vue 日期选择器DatePicker传给后台日期参数格式问题

花了一个下午才解决&#xff0c;官方组件文档里面是没有处理方案说明的。 项目版本&#xff1a;Ant Design Vue 2.0.2 前端部分代码&#xff1a; <template><a-modal:visible"visible":width"windowWidth":height"800":title"tit…...

springboot1.5.12升级至2.6.15

首先&#xff0c;加入springboot升级大版本依赖&#xff0c;会在升级过程中打印出错日志提示&#xff08;升级完毕可去除&#xff09; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-properties-migrator</art…...

Android Event事件分发(新版本)

之前写过一个方案&#xff08;添加链接描述&#xff09;&#xff0c;突然觉得很麻烦&#xff0c;于是有了新的方案&#xff1a; 首先先说要解决的问题&#xff1a; 当父布局能滑动&#xff0c;子View也能滑动&#xff0c;就会出现滑动冲突 解决思路&#xff1a;我们按下子Vie…...

可控生成:ControlNet原理

🤗关注公众号funNLPer体验更佳阅读🤗 论文:Adding Conditional Control to Text-to-Image Diffusion Models 代码:lllyasviel/ControlNet 简单来说ControlNet希望通过输入额外条件来控制大型图像生成模型,使得图像生成模型根据可控。 文章目录 1. 动机2. ControlNet原理…...

【极客时间】MySQL 必知必会-20230901

03 | 表&#xff1a;怎么创建和修改数据表&#xff1f; 新增数据表 CREATE DATABASE demo;CREATE TABLE goodsmaster (barcode TEXT,goodsname TEXT,price DOUBLE, itemnumber INT PRIMARY KEY AUTO_INCREMENT);INSERT INTO demo.goodsmaster (barcode, goodsname,price) VAL…...

53 个 CSS 特效 3(完)

53 个 CSS 特效 3&#xff08;完&#xff09; 前两篇地址&#xff1a; 53 个 CSS 特效 153 个 CSS 特效 2 这里是第 33 到 53 个&#xff0c;很多内容都挺重复的&#xff0c;所以这里解释没之前的细&#xff0c;如果漏了一些之前的笔记会补一下&#xff0c;写过的就会跳过。…...

简单数学题:找出最大的可达成数字

来看一道简单的数学题&#xff1a;力扣2769. 找出最大的可达成数字 题目描述的花里胡哨&#xff0c;天花乱坠&#xff0c;但这道题目非常简单。我们最多执行t次操作&#xff0c;只需每次操作都让x-1&#xff0c;让num1&#xff0c;执行t次操作后&#xff0c;x就变为xt&#xff…...

[C++ 网络协议] 套接字的多种可选项

目录 1. 套接字的可选项 2. 获取/设置套接字可选项 2.1 getsockopt函数&#xff08;获取套接字可选项&#xff09; 2.2 setsockopt函数&#xff08;设置套接字可选项&#xff09; 3. 常用套接字可选项 3.1 SOL_SOCKET协议层的SO_TYPE可选项 3.2 SOL_SOCKET协议层的SO_SN…...

2022年03月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:数字变换 给定一个包含 5 个数字(0-9)的字符串, 例如 “02943”, 请将“12345”变换到它。 你可以采取 3 种操作进行变换 (1)交换相邻的两个数字 (2)将一个数字加 1。 如果加 1 后大于 9, 则变为 0 (3)将一个数字加倍。 如果加倍后大于 9,则将其变为加倍后的…...

***数据转换中常用的两个函数 sscanf,sprintf

1、sscanf将字符串转换成想要的整数或浮点数 (HMI屏中输入浮点数据,到mcu后要转换成对应的浮点数据) sscanf(“0.9”,“%f”,getData) /*! \brief 文本控件通知 \details 当文本通过键盘更新(或调用GetControlValue)时,执行此函数 \details 文本控件的内容以字符串形…...

软件工程(十九) 软件测试

软件测试主要了解软件测试的方法和软件的调试。 1、软件测试方法 1.1、测试基本思想 尽早、不断的进行测试 在V模型其实已经凸显出这种思想了程序员避免测试自己设计的程序 因为测试自己设计的程序,其实是不容易发现问题的,因为人从本质上都不愿意找自己的茬。而且由于你的…...

go中读写锁(rwmutex)源码解读实现原理

go读写锁的实现原理 1、RWMutex读写锁的概念 读写锁也就是我们所使用的RWMutex&#xff0c;其实是对于go本身的mutex做的一个拓展&#xff0c;当一个goroutine获得了读锁后&#xff0c;其他goroutine同样可以获得读锁&#xff0c;但是不能获得写锁。相反&#xff0c;当一个go…...

【人工智能】—_深度优先搜索、代价一致搜索、深度有限搜索、迭代深度优先搜索、图搜索

【人工智能】无信息搜索—BFS 、代价一致、DFS、深度受限、迭代深入深度优先、图搜索 什么是搜索 搜索问题是指既不能通过数学建模解决&#xff0c;又没有其他算法可以套用或者非遍历所有情况才能得出正确结果。这时就需要采用搜索算法来解决问题。搜索就是一种通过穷举所有解…...

uni-app 客服按钮可上下拖动动

项目需求&#xff1a; 因为悬浮客服有时候会遮挡住界面内容&#xff0c;故需要对悬浮的气泡弹窗做可拖动操作 movable-area&#xff1a;可拖动区域 movable-view&#xff1a;可移动的视图容器&#xff0c;在页面中可以拖拽滑动或双指缩放。 属性说明 属性名类型默认值说…...

基于Android的旅游管理系统 微信小程序

随着网络科技的发展&#xff0c;移动智能终端逐渐走进人们的视线&#xff0c;相关应用越来越广泛&#xff0c;并在人们的日常生活中扮演着越来越重要的角色。因此&#xff0c;关键应用程序的开发成为影响移动智能终端普及的重要因素&#xff0c;设计并开发实用、方便的应用程序…...

python-数据可视化-下载数据-CSV文件格式

数据以两种常见格式存储&#xff1a;CSV和JSON CSV文件格式 comma-separated values import csv filename sitka_weather_07-2018_simple.csv with open(filename) as f:reader csv.reader(f)header_row next(reader)print(header_row) # [USW00025333, SITKA AIRPORT, A…...

时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测

时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测 目录 时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现SSA-XGBoost时间序列预测&#xff0c;麻…...

leetcode 823 带因子的二叉树

用动态规划 如果两个节点值不同,要乘2&#xff0c;因为两个节点可以互换位置 dp[i] dp[left] * dp[right] * 2 如果相同 dp[i] dp[left] * dp[right] class Solution {public int numFactoredBinaryTrees(int[] arr) {Arrays.sort(arr);int n arr.length;long[] dp ne…...

钉钉消息已读、未读咋实现的嘞?

前言 一款app&#xff0c;消息页面有&#xff1a;钱包通知、最近访客等各种通知类别&#xff0c;每个类别可能有新的通知消息&#xff0c;实现已读、未读功能&#xff0c;包括多少个未读&#xff0c;这个是怎么实现的呢&#xff1f;比如用户A访问了用户B的主页&#xff0c;难道…...

Java 读取TIFF JPEG GIF PNG PDF

Java 读取TIFF JPEG GIF PNG PDF 本文解决方法基于开源 tesseract 下载适合自己系统版本的tesseract &#xff0c;官网链接&#xff1a;https://digi.bib.uni-mannheim.de/tesseract/ 2. 下载之后安装&#xff0c;安装的时候选择选择语言包&#xff0c;我选择了中文和英文 3.…...

研磨设计模式day14模板方法模式

目录 场景 原有逻辑 有何问题 解决方案 解决思路 代码实现 重写示例 模板方法的优缺点 模板方法的本质 何时选用 场景 现在模拟一个场景&#xff0c;两个人要登录一个系统&#xff0c;一个是管理员一个是用户&#xff0c;这两个不同身份的登录是由后端对应的两个接…...

7 集群基本测试

1. 上传小文件到集群 在hadoop路径下执行命令创建一个文件夹用于存放即将上传的文件&#xff1a; [atguiguhadoop102 ~]$ hadoop fs -mkdir /input上传&#xff1a; [atguiguhadoop102 hadoop-3.1.3]$ hadoop fs -put wcinput/work.txt /input2.上传大文件 [atguiguhadoop1…...

chrono学习(一)

我想用chrono进行沙土的仿真&#xff0c;首先学习demo_GPU_ballCosim.cpp&#xff0c;这个例子仿真了一些沙土的沉降过程。 首先&#xff0c;运行编辑完成的文件demo_GPU_ballCosim&#xff1a; (base) eowyneowyn-MS-7D20:~/build_chrono/bin$ ./demo_GPU_ballCosim 运行完得…...

后端面试话术集锦第 十 篇:springMVC面试话术

这是后端面试集锦第十篇博文——springMVC面试话术❗❗❗ 1. 介绍一下springMVC springmvc是一个视图层框架,通过MVC模型让我们很方便的接收和处理请求和响应。 我给你说说他里边的几个核心组件吧: 它的核心控制器是DispatcherServlet,他的作用是接收用户请求,然后给用户…...

基于Django 框架搭建的机器学习在线平台源代码+数据库,实现KNN、ID3、C4.5、SVM、朴素贝叶斯、BP神经网络等算法及流程管理

结果展示&#xff08;Kmeans&#xff09;&#xff1a; 完整代码下载地址&#xff1a;基于Django 框架搭建的机器学习在线平台源代码数据库 python机器学习之 K-邻近算法 简单的理解&#xff1a;[ 采用测量不同特征值之间的距离方法进行分类 ] 优点 &#xff1a;精度高、对异常…...

大数据组件-Flume集群环境搭建

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…...