MySQL索引优化实战

联合索引第一个字段用范围不会走索引 type = all

EXPLAIN SELECT * FROM employees 
WHERE name > 'LiLei' AND age = 22 AND position ='manager';

因为MySQL有自己的优化机制,当索引中第一个字段是 大于 小于 那么MySQL就会认为会扫描出很多条数据 并且是二级索引可能还要回表,那么多数据需要回表还不如不走当前使用索引直接走主键索引全表扫描

强制索引

EXPLAIN SELECT * FROM employees 
force index(idx_name_age_position) 
WHERE name > 'LiLei' AND age = 22 AND position ='manager';

因为where中第一个是name 原本应该走索引但是因为 使用的是范围查询 MySQL认为索引第一个字段就是范围查询 计算得出成本比全表扫描成本还大 就会走全表扫描

但是如果MySQL计算成本错误,走索引还是比较快的 那么我们可以强制让MySQL走索引。

使用 force index(索引名称) 就会强制走索引

MySQL走不走索引也会跟 name > 'LiLei' 得出的数据多少有关 如果很多 但是后面还有字段 age作为条件 这时候就会全表扫描,后面age = 22 是肯定不能走索引了,因为前边 使用 name > 'LiLei' 已经让age无序了

使用索引优化

select 后面不要跟 * ,尽量使用二级索引中索引字段 这样不需要回表

in和or在表数据量比较大的情况会走索引,在表记录不多的情况下会选择全表扫描

因为 数据比较少的话 MySQL认为走in 还要回表 并且数据本身就少 直接全表查询也比较容易就那么点数据 还不需要回表 并且 in 还可能包好全表数据 所以MySQL在数据少的情况下会全表

如果数据量大,那么走索引还是比较快的,因为那么多数据 走 in 索引比全表扫描成本低

like 'KK%' 一般情况都会走索引

假设表中有联合索引:index_test(name,age,gend);

where name like 'KK%' and age = 10 and gend = '男';

like 'kk%'走索引是因为MySQL中都是排好序的 通过 'kk%'其实就是相当于是一个 范围查询 的意思,但是MySQL会认为 模糊查询得到的数据量会比 > 、< 这种得到的数据量小 所以会走索引但是第一个字段是 <、>不走索引

索引下推(ICP)

MySQL5.6版本之前 使用的是 二级索引name找到的所有主键id 去回表主键索引

MySQL5.6版本之后使用的是 二级索引name匹配到符合的值以后再根据后面的 age 和 gend再过滤拿到最终的主键id去主键索引中回表 这样的好处就是回表的时候主键id会减少。

like 'kk%' 会走索引下推

<、>不走索引下推 因为MySQL认为 like 'kk%' 已经过滤掉很多数据了 所以走索引下推,而 <、>认为过滤以后还有很多数据 这样还不如全表查询还需要回表 所以不走索引并且不走索引下推

范围查询不会走索引下推,因为MySQL认为范围查询数据量会比较多,所以不走索引

查看MySQL 成本计算方式

set session optimizer_trace="enabled=on",end_markers_in_json=on; ‐‐开启trace
select * from employees where name > 'a' order by position;
SELECT * FROM information_schema.OPTIMIZER_TRACE;

第一句第三句固定写死 第二句是要执行的sql

{"steps": [{"join_preparation": { ‐‐第一阶段:SQL准备阶段,格式化sql"select#": 1,"steps": [{"expanded_query": "/* select#1 */ select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`empl
oyees`.`age` AS `age`,`employees`.`position` AS `position`,`employees`.`hire_time` AS `hire_time` from
`employees` where (`employees`.`name` > 'a') order by `employees`.`position`"}] /* steps */} /* join_preparation */},{"join_optimization": { ‐‐第二阶段:SQL优化阶段"select#": 1,"steps": [{"condition_processing": { ‐‐条件处理"condition": "WHERE","original_condition": "(`employees`.`name` > 'a')","steps": [{"transformation": "equality_propagation","resulting_condition": "(`employees`.`name` > 'a')"},{"transformation": "constant_propagation","resulting_condition": "(`employees`.`name` > 'a')"},{"transformation": "trivial_condition_removal","resulting_condition": "(`employees`.`name` > 'a')"}] /* steps */} /* condition_processing */},{"substitute_generated_columns": {} /* substitute_generated_columns */},{"table_dependencies": [ ‐‐表依赖详情{"table": "`employees`","row_may_be_null": false,"map_bit": 0,"depends_on_map_bits": [] /* depends_on_map_bits */}] /* table_dependencies */},{"ref_optimizer_key_uses": [] /* ref_optimizer_key_uses */},{"rows_estimation": [ ‐‐预估表的访问成本{"table": "`employees`","range_analysis": {"table_scan": { ‐‐全表扫描情况"rows": 10123, ‐‐扫描行数"cost": 2054.7 ‐‐查询成本} /* table_scan */,"potential_range_indexes": [ ‐‐查询可能使用的索引{"index": "PRIMARY", ‐‐主键索引"usable": false,"cause": "not_applicable"},{"index": "idx_name_age_position", ‐‐辅助索引"usable": true,"key_parts": ["name","age","position","id"] /* key_parts */}] /* potential_range_indexes */,"setup_range_conditions": [] /* setup_range_conditions */,"group_index_range": {"chosen": false,"cause": "not_group_by_or_distinct"} /* group_index_range */,"analyzing_range_alternatives": { ‐‐分析各个索引使用成本"range_scan_alternatives": [{"index": "idx_name_age_position","ranges": ["a < name" ‐‐索引使用范围] /* ranges */,"index_dives_for_eq_ranges": true,"rowid_ordered": false, ‐‐使用该索引获取的记录是否按照主键排序"using_mrr": false,"index_only": false, ‐‐是否使用覆盖索引"rows": 5061, ‐‐索引扫描行数"cost": 6074.2, ‐‐索引使用成本"chosen": false, ‐‐是否选择该索引"cause": "cost"}] /* range_scan_alternatives */,"analyzing_roworder_intersect": {"usable": false,"cause": "too_few_roworder_scans"} /* analyzing_roworder_intersect */} /* analyzing_range_alternatives */} /* range_analysis */}] /* rows_estimation */},{"considered_execution_plans": [{"plan_prefix": [] /* plan_prefix */,"table": "`employees`","best_access_path": { ‐‐最优访问路径"considered_access_paths": [ ‐‐最终选择的访问路径{"rows_to_scan": 10123,"access_type": "scan", ‐‐访问类型:为scan,全表扫描"resulting_rows": 10123,"cost": 2052.6,"chosen": true, ‐‐确定选择"use_tmp_table": true}] /* considered_access_paths */} /* best_access_path */,"condition_filtering_pct": 100,"rows_for_plan": 10123,"cost_for_plan": 2052.6,"sort_cost": 10123,"new_cost_for_plan": 12176,"chosen": true}] /* considered_execution_plans */},{"attaching_conditions_to_tables": {"original_condition": "(`employees`.`name` > 'a')","attached_conditions_computation": [] /* attached_conditions_computation */,"attached_conditions_summary": [{"table": "`employees`","attached": "(`employees`.`name` > 'a')"}] /* attached_conditions_summary */} /* attaching_conditions_to_tables */},{"clause_processing": {"clause": "ORDER BY","original_clause": "`employees`.`position`","items": [{"item": "`employees`.`position`"}] /* items */,"resulting_clause_is_simple": true,"resulting_clause": "`employees`.`position`"} /* clause_processing */},{"reconsidering_access_paths_for_index_ordering": {"clause": "ORDER BY","steps": [] /* steps */,"index_order_summary": {"table": "`employees`","index_provides_order": false,"order_direction": "undefined","index": "unknown","plan_changed": false} /* index_order_summary */} /* reconsidering_access_paths_for_index_ordering */},{"refine_plan": [{"table": "`employees`"}] /* refine_plan */}] /* steps */} /* join_optimization */},{"join_execution": { ‐‐第三阶段:SQL执行阶段"select#": 1,"steps": [] /* steps */} /* join_execution */}] /* steps */}结论:全表扫描的成本低于索引扫描,所以mysql最终选择全表扫描mysql> select * from employees where name > 'zzz' order by position;mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE;查看trace字段可知索引扫描的成本低于全表扫描,所以mysql最终选择索引扫描mysql> set session optimizer_trace="enabled=off"; ‐‐关闭trace

group by

order by

使用最左前缀原则,这样会走索引 并且 exra是可以看到 走没走索引 如果走了索引就是 using index

比如有索引 name,age,gender

sql: select name,age from employ order by age;

上边 sql就是using filesort。代表是加载到内存或者硬盘排序。

sql: select name,age from employ order by name,age;

这个sql就是走的 using index 索引排序 因为索引本身就是排好序的。但是要最左前缀原则,不然不走索引。因为就变成无序了

sql: select name,age from employ where name = 'aa' order by age;

这个sql其实order by并没有最左前缀,因为第一个应该是name但是跳过了name。但是还是using index,因为name就是一个常量 aa ,MySQL会进行优化这样就是最左前缀了。

如果是 using filesort

代表可能是内存排序或者硬盘排序。

MySQL内存排序

因为使用的是using filesort排序,所以MySQL会先开辟出来一块内存 sort_buffer 默认1M,用来存放需要排序的数据

单双链路

mysql会通过max_length_for_sort_data

using_filesort 是将数据加载到sort_buffer中进行排序的,

单链路是将 需要排序的数据整行数据加载到sort_buffer,

双链路是将需要排序的数据主键和需要排序的字段加载到sort_buffer中进行排序,排完序再通过主键给主键索引中找到该数据。也是回表排序

mysql会通过max_length_for_sort_data 来判断使用什么排序。默认是1024字节,如果一行数据大于1024字节,那么就会走双链路排序,如果小于那就走单链路排序

单链路排序肯定比双链路排序快,因为不用回表,但是如果一行数据太大就比较占用内存所以使用双链路直接在主键和需要排序的字段。

如果sort_buffer 默认1M空间承受不了需要排序的数据,就会创建一个临时文件,先排序一部分放到文件中再取出一部分放到内存sort_buffer排序,最后合并成整个排好序的数据

MySQL索引设计原则

1、代码先行,索引后上 不知大家一般是怎么给数据表建立索引的,是建完表马上就建立索引吗? 这其实是不对的,一般应该等到主体业务功能开发完毕,把涉及到该表相关sql都要拿出来分析之后再建立 索引。

2、联合索引尽量覆盖条件 比如可以设计一个或者两三个联合索引(尽量少建单值索引),让每一个联合索引都尽量去包含sql语句里的 where、order by、group by的字段,还要确保这些联合索引的字段顺序尽量满足sql查询的最左前缀原 则。

3、不要在小基数字段上建立索引 索引基数是指这个字段在表里总共有多少个不同的值,比如一张表总共100万行记录,其中有个性别字段, 其值不是男就是女,那么该字段的基数就是2。 如果对这种小基数字段建立索引的话,还不如全表扫描了,因为你的索引树里就包含男和女两种值,根本没 法进行快速的二分查找,那用索引就没有太大的意义了。 一般建立索引,尽量使用那些基数比较大的字段,就是值比较多的字段,那么才能发挥出B+树快速二分查 找的优势来。

4、长字符串我们可以采用前缀索引 尽量对字段类型较小的列设计索引,比如说什么tinyint之类的,因为字段类型较小的话,占用磁盘空间也会 比较小,此时你在搜索的时候性能也会比较好一点。 当然,这个所谓的字段类型小一点的列,也不是绝对的,很多时候你就是要针对varchar(255)这种字段建立 索引,哪怕多占用一些磁盘空间也是有必要的。 对于这种varchar(255)的大字段可能会比较占用磁盘空间,可以稍微优化下,比如针对这个字段的前20个 字符建立索引,就是说,对这个字段里的每个值的前20个字符放在索引树里,类似于 KEY index(name(20),age,position)。 此时你在where条件里搜索的时候,如果是根据name字段来搜索,那么此时就会先到索引树里根据name 字段的前20个字符去搜索,定位到之后前20个字符的前缀匹配的部分数据之后,再回到聚簇索引提取出来 完整的name字段值进行比对。 但是假如你要是order by name,那么此时你的name因为在索引树里仅仅包含了前20个字符,所以这个排 序是没法用上索引的, group by也是同理。所以这里大家要对前缀索引有一个了解。

5、where与order by冲突时优先where 在where和order by出现索引设计冲突时,到底是针对where去设计索引,还是针对order by设计索引?到 底是让where去用上索引,还是让order by用上索引? 一般这种时候往往都是让where条件去使用索引来快速筛选出来一部分指定的数据,接着再进行排序。 因为大多数情况基于索引进行where筛选往往可以最快速度筛选出你要的少部分数据,然后做排序的成本可 能会小很多。

分页查询

在使用分页查询时,比如会写

sql select * FROM employees LIMIT 9000,10 ORDER BY id;

因为id是主键,所以是有序的,order by还比较快,但是limit MySQL是查询出来9010条数据,扔掉9000条数据,这样查询是比较慢的

我们可以使用联合索引走索引覆盖

sql select id FROM employees LIMIT 9000,10 ORDER BY id;

但是如果我们查询并不是只要id 而是id、name、age、gender。但是如果这样就不能走 覆盖索引了。

优化方案:select * FROM employees emp inner join (select id FROM employees ORDER BY id LIMIT 9000,10 ) tem ON emp.id = tem.id

这样最外层的数据使用主键关联,走的主键索引肯定很快,里面的sql走的覆盖索引不需要回表完成优化

单位遇到的优化方案: 因为是使用的id进行排序取值 可以将id返回给前端,前端分页的时候将最后一个id作为参数带给后端。 比如最后一条id=9000

sql select * FROM employees WHERE id > 9000 ORDER BY id LIMIT 10;

如果只是limit 10 条数据,回表次数也不多,我理解是不需要再去联合。这样走了主键索引而且也每次取10条。

inner查询优化 挤走索引又查询全部字段

select * FROM employees emp inner join (select id FROM employees ORDER BY id LIMIT 9000,10 ) tem ON emp.id = tem.id

上边sql 中 子查询 只返回id可以走覆盖索引不需要回表,在根据主键id联合 走主键索引找到全部数据。

这种情况我理解是需要扫描数据多,导致回表次数多,使用改方案。

NLG和BLG

比如A 有 10万条数据 B 100条数据

sql: select * from A inner join B on A.id = B.id;

MySQL会根据 联合字段有没有走索引来判断走那种算法。 比如A表中id为索引,那么就走NLG,如果不为索引,就要走无序的磁盘扫描,每扫描一次A表就相当于扫描10万行记录。所以就会走BLG

NLG

也就是索引链接。是内嵌套连接

这条sql语句执行逻辑为:

for(select id from B){

select * from A where id = B.id

}

第一步: B中去一条数据

第二步: 拿到B数据的id字段给A表中通过主键id查询 主键索引很快,几乎相当于常量查询

第三步: 在A中找到的那条数据

上边可以看出,B表越小越好,因为B越小循环次数越少。所以上边这条sql语句适合小表在后,大表在前,小表先执行,大表后执行。但是如果没有索引MySQL会执行BLG算法

假设走索引id为主键索引,如果B表中 有100条数据,A表中有100000条数据。那么执行的时候,会先全表扫描B表加载在内存中,再逐一取出一条数据去主键索引中寻找数据 。

也就是第一次全表扫描需要扫描 100 条数据,第二步通过每一条数据给A表中主键查询,每查询一次都相当于100,那么为什么给A表查询一次相当于一次查询,不应该扫描100000数据找到和取出的数据id相等的那条数据吗?那是因为主键索引非常快,通过主键索引查询非常快,几乎是常量查询,所以每查询一次主键索引相当于查询一次常量。所以 100 条数据查询完了也就相当于查询了100次A表。所以整个查询只用了200

BLG

比如上边sql中id不是索引只是普通字段。会将B表中的100行记录全表扫描放到join_buffer中。全表扫描100次,再去扫描A中10万行记录,每扫描一条就去A中join_buffer中比对id是否相同,相同就纪录下来。又因为A在join_buffer是无序的,那么就会没扫描一次A就是相当于扫描100行记录取出id和A中该数据id相等的数据。而A有需要扫描10万次,所以一共也就是 扫描A 10万次 + B 100 条 * 10万次 + 全表扫描B加入到join_buffer的100条 = 1100100 一百多万次

如果没有索引但是走NLG算法是什么样子的

索引取到B表100数据加载到 join_buffer 扫描100记录

每取出一条B表一条记录就去A表查询id相等的数据,注意这里id是普通字段不是索引。所以每查询一次就是10万条数据中找到id和当前B中取到的这条数据相等的数据。也就是 取B表100条数据需要重复 给A表10万数据查询100次也就是需要 100 * 10万 = 1000万次。并且还是磁盘扫描这么多。肯定性能不高

exit和in

exits

exit 是 select * from A where exits (select 1 from B where A.id = B.id)

相当于:

for (select * from A){

select 1 from B where B.id = A.id;

}

从上边可以看出,A表数据越小越好,因为A表越少循环次数越少,查询次数也就越少。

所以exits适合前边表小,后面表大的。

in

select * from A where A.id in (select id from B)

相当于

for(select id from B){

select * from A where A.id = B.id;

}

显然这种想要查询次数少需要B表中数据少,因为B表中数据少,就会减少循环次数从而减少查询次数。

这种数据适合于子后面表小,前边表达的sql。

count(*)、count(1)、count(字段)、count(主键)

这四种其实都是走的二级索引,因为二级索引占用内存少

如果 count(字段) 字段是索引的话: count(*)约等于 count(1) > count(字段) > count(主键)

count(*) 做了优化,就是扫描的时候,记录行数,二级索引中 扫描到一行就是 +1 不用取到某一个字段

count(1) 也是扫描到一行就 +1 不用取到某一个字段

count(字段) 因为字段是索引所以会走二级索引,所以不用回表就能取到该字段,取到这个字段才会进行+1 因为要取到 这个字段才能进行 +1 所以会比 count(*) count(1)慢

count(id) 5.7版本之前是走的主键索引,之后做了优化也是二级索引。然后取出id值进行+1

为什么 count (id) 比同是走二级索引并且 count(字段) 要慢呢?个人理解因为 count要去非叶子节点取出id,而count(字段)是扫描一条数据就是一条数据 不找非叶子节点。就可以取出字段进行+1所以会快

如果字段不走索引:

count(*)约等于 count(1) > count(主键) > count(字段)

这时候就是扫描主键索引,因为字段没有索引肯定是最慢的。

个人学习笔记,如有错误欢迎大佬指正

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

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

相关文章

EtherCAT主站SOEM -- 16 --Qt-Soem通过界面按键控制电机转圈圈PV模式

EtherCAT主站SOEM -- 16 --Qt-Soem通过界面按键控制电机转圈圈 0 QT-SOEM视频预览及源代码下载:0.1 QT-SOEM视频预览0.2 QT-SOEM源代码下载1 程序文件修改替换1.1 allvalue.h1.2 motrorcontrol.h1.3 mainwindow.cpp1.4 motrorcontrol.cpp2 ui界面显示该文档修改记录:总结上下…

STM32——高级定时器输出指定个数PWM波原理及实战

1.高级定时器简介&#xff08;TIM8、TIM1&#xff09; 相比于通用定时器特性&#xff1a; 1&#xff09;重复计数器 2&#xff09;死区时间带可编程的互补输出 3&#xff09;断路输入&#xff0c;用于将定时器的输出信号置于用户可选的安全配置中 2.高级定时器框图 3.重复计数…

Sectigo增强型多域名SSL证书买一年送一月

Sectigo EV增强型多域名SSL证书是一种高安全性的数字证书。相比于DV基础型的多域名SSL证书和OV企业型的多域名SSL证书&#xff0c;EV增强型多域名SSL证书功能更多、安全等级更高&#xff0c;但是相应的&#xff0c;这款SSL证书的审核也比较严格。今天就随SSL盾小编了解Sectigo旗…

Oracle篇—实例中和name相关参数的区别和作用

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

基于JAVA开发的数字化智慧工地管理平台源码,可私有化部署、带可视化大屏

智能工地应用价值 智慧工地现场构建了基于物联网的智能化数据传感器通用的管理平台。利用计算机、人工智能、无线通信&#xff0c;全天候现场监视、施工检查、质量管理、服务&#xff0c;提高数字化管理、安全、绿色、施工等现场管理能力&#xff0c;标志着现场管理进入信息化时…

YOLOV8在coco128上的训练

coco128是coco数据集的子集只有128张图片 训练代码main.py from ultralytics import YOLO# Load a model model YOLO("yolov8n.yaml") # build a new model from scratch model YOLO("yolov8n.pt") # load a pretrained model (recommended for trai…

20240106----重返学习-在VMware里给centos7设置静态IP地址

在VMware里给centos7设置静态IP地址 场景 学习nginx中&#xff0c;想要设置静态IP地址&#xff0c;以便让win10主环境中的Xshell里能够连接到VMware中的CentOS7上&#xff0c;进而可以在Xshell里进行操作。可以做到如复制粘贴之类的&#xff0c;而不是在虚拟机中的默认终端上…

css如何让两个元素在同一水平线上(文字和svg图片)

一开始写发现这两者不在同一水平线 起初用margin-top margin-bottom来协调 发现效果并不好 1&#xff1a;写法僵硬 2&#xff1a;margin会把div撑破&#xff0c;达不到预期效果&#xff08;padding也是&#xff09; 3. 加了flex布局 之后, 因为我这个是在表格里面,无法居中…

实录分享 | 央企大数据平台架构发展趋势与应用场景的介绍

分享嘉宾&#xff1a; 孟子涵-中国华能集团信息中心平台架构师 2021年华能就与Alluxio建立了合作&#xff0c;共同写了整个华能统一纳管的架构方案。这个方案我认为是现在我们在央企里边比较核心的一套体系&#xff0c;能让全集团所有我们认为重要的数字化资源实现真正的统一集…

Laravel中的lockForUpdate悲观锁

lockForUpdate 是悲观锁&#xff0c;测试就不写了 注意的事项 lockForUpdate 必须在事务中lockForUpdate 被阻塞的查询必须是同样添加了lockForUpdate的语句查询语句走索引&#xff0c;则使用行锁&#xff0c;否则使用表锁 现在举例说明第一项和第二项 开启事务并添加锁 pub…

【K8s学习】

k8s的简单执行流程&#xff1a; Kubernetes Master&#xff08;API Server、Scheduler等组件&#xff09;负责调度Pod到合适的Node上。 当Pod被调度到某个Node时&#xff0c;该Node上的kubelet代理会收到指令并开始执行Pod的生命周期管理任务&#xff0c;包括创建、监控和终止P…

第8章-第4节-Java中字节流的缓冲流

1、缓冲流&#xff1a;属于高级IO流&#xff0c;并不能直接读写数据&#xff0c;需要依赖于基础流。缓冲流的目的是为了提高文件的读写效率&#xff1f;那么是如何提高文件的读写效率的呢&#xff1f; 在内存中设置一个缓冲区&#xff0c;缓冲区的默认大小是8192字节&#xff…

第 3 章 Keepalived 双机热备

技能展示&#xff1a; 会构建双机热备系统 会构建 LVSHA 高可用群集 在这个高度信息化的 IT 时代&#xff0c;企业的生产系统、业务运营、销售和支持&#xff0c;以及日常管理等环节越来越依赖于计算机信息和服务&#xff0c;对高可用&#xff08;HA&#xff09;技术的应用需求…

Nginx+Tomcat负载均衡、动静分离以及Nginx负载均衡和四层代理

目录 NginxTomcat负载均衡、动静分离 Nginx 负载均衡模式&#xff1a; Nginx 四层代理配置&#xff1a; NginxTomcat负载均衡、动静分离 Nginx 服务器&#xff1a;192.168.80.10:80 Tomcat服务器1&#xff1a;192.168.80.100:80 Tomcat服务器2&#xff1a;192.168.80.101:80…

前端安全专题

xss (Cross Site Scripting) 跨站脚本攻击 原理 通常指黑客通过"HTML注入"篡改了网页&#xff0c;插入了恶意的脚本&#xff0c;从而在用户浏览网页时&#xff0c;控制用户浏览器的一种攻击。 常见攻击类型 存储型XSS 攻击者将恶意的 JavaScript 脚本存储在网站…

【分布式微服务专题】SpringSecurity OAuth2快速入门

目录 前言阅读对象阅读导航前置知识笔记正文一、OAuth2 介绍1.1 使用场景*1.2 基本概念&#xff08;角色&#xff09;1.3 优缺点 二、OAuth2的设计思路2.1 客户端授权模式2.1.0 基本参数说明2.1.1 授权码模式2.1.2 简化&#xff08;隐式&#xff09;模式2.1.3 密码模式2.1.4 客…

Go 语言中的锁

1. 并发基础 并发是同时发生多个计算或事件的能力。并发通常通过同时执行多个任务或进程来实现&#xff0c;这些任务或进程共享相同的资源&#xff08;例如内存或处理器&#xff09;。并发使用的基本机制被称为锁。在Go语言中&#xff0c;锁是一个类型变量&#xff0c;它包含一…

Redis 淘汰策略有哪些?

Redis 淘汰策略有哪些&#xff1f; Redis 中有多种淘汰策略&#xff08;Eviction Policy&#xff09;&#xff0c;用于在内存不足时选择要移除的键值对。以下是一些常见的淘汰策略&#xff1a; No Eviction&#xff08;无淘汰&#xff09;&#xff1a; 默认策略&#xff0c;当…

如何使用人工智能优化 DevOps?

DevOps 和人工智能密不可分&#xff0c;影响着各种业务。DevOps 可以加快产品开发速度并简化现有部署的维护&#xff0c;而 AI 则可以改变整个系统的功能。DevOps团队可以依靠人工智能和机器学习来进行数据集成、测试、评估和发布系统。更重要的是&#xff0c;人工智能和机器学…

轻松掌握构建工具:Webpack、Gulp、Grunt 和 Rollup 的使用技巧(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…