mysql之规则优化器RBO
文章目录
- MySQL 基于规则的优化 (RBO):
- RBO 的核心思想:模式匹配与规则应用
- RBO 的主要优化规则
- 查询重写 (Query Rewrite) / 查询转换 (Query Transformation)
- 子查询优化 (Subquery Optimization) - RBO 的重中之重
- 非相关子查询 (Non-Correlated Subquery) 优化
- 相关子查询 (Correlated Subquery) 的优化 (有限的 RBO 优化)
- 视图合并 (View Merging)
- 条件化简 (Predicate Simplification)
- 外连接消除 (Outer Join Elimination)
- 其他查询重写规则
- 访问路径选择 (Access Path Selection) - RBO 的早期角色 (现在更多由 CBO 负责)
- JOIN 顺序优化 (Join Order Optimization) - RBO 的早期角色 (现在更多由 CBO 负责)
- RBO vs. CBO:各有千秋,协同工作
- RBO 的局限性与 CBO 的优势
- RBO 优化指导与实践建议
- 子查询优化
- 子查询语法
- 按返回结果集区分
- 按与外层查询关系区分
- 子查询在布尔表达式中的使用
- 子查询在 MySQL 中的执行方式
- 实战优化技巧
- IN vs EXISTS选择
- 派生表优化
- 优化验证工具
- 实际使用建议
- 总结
MySQL 基于规则的优化 (RBO):
MySQL 查询优化器除了成本优化 (CBO) 外,还包含一套基于规则的优化 (Rule-Based Optimization, RBO) 策略。RBO 就像 SQL 查询的 “整形医生”,依据预定义的规则,对查询进行快速的语法和语义转换,提升查询效率。
RBO 的核心思想:模式匹配与规则应用
RBO 的核心是 模式匹配 (Pattern Matching) 与规则应用 (Rule Application)。优化器预定义了一系列优化规则, 描述特定 SQL 模式的优化转换方式。优化器解析 SQL 查询时, 会尝试将查询与 RBO 规则进行匹配。如果匹配成功,则应用规则,对查询进行改写, 生成一个语义等价但可能更高效的新查询。
RBO 的主要优化规则
查询重写 (Query Rewrite) / 查询转换 (Query Transformation)
这是 RBO 最核心的功能,通过改写 SQL 语句本身来优化。
子查询优化 (Subquery Optimization) - RBO 的重中之重
子查询是常见的性能瓶颈。RBO 针对不同类型的子查询,应用不同的优化规则。
非相关子查询 (Non-Correlated Subquery) 优化
子查询的执行不依赖于外部查询的表。RBO 倾向于将非相关子查询 物化 (Materialization) 或 转换为连接 (Unnesting)。
IN
** 子查询转换为**JOIN**
(Subquery Unnesting - IN to JOIN)😗* 将WHERE column IN (SELECT ...)
形式的非相关IN
子查询,转换为等价的INNER JOIN
或LEFT SEMI JOIN
。
-- 原始 SQL (IN 子查询)SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE region = 'North');-- RBO 转换后的 SQL (JOIN)SELECT o.* FROM orders oINNER JOIN customers c ON o.customer_id = c.customer_idWHERE c.region = 'North';
机制详解: RBO 识别出 IN 子查询是非相关的,并且子查询的目的是过滤 orders 表的 customer_id。 因此,它将子查询提取出来,与外部查询的 orders 表进行 INNER JOIN 连接,连接条件是 o.customer_id = c.customer_id。 WHERE c.region = ‘North’ 条件被保留。
SELECT * FROM orders o WHERE o.customer_id IN (SELECT c.customer_id FROM customers c WHERE c.coutry=o.contry);
注:当子查询引用了外部查询的列时(相关子查询),其结果依赖于外部查询的每一行,外部查询每一行都需要执行一次子查询,非相关子查询
EXISTS
** 子查询转换为**JOIN**
(Subquery Unnesting - EXISTS to JOIN)😗* 将WHERE EXISTS (SELECT ...)
形式的非相关EXISTS
子查询,转换为LEFT SEMI JOIN
。
-- 原始 SQL (EXISTS 子查询)SELECT * FROM departments WHERE EXISTS (SELECT * FROM employees WHERE dept_id = departments.dept_id AND salary > 100000);-- RBO 转换后的 SQL (LEFT SEMI JOIN)SELECT d.* FROM departments dLEFT SEMI JOIN employees e ON d.dept_id = e.dept_id AND e.salary > 100000;
机制详解: EXISTS 子查询用于判断是否存在满足条件的记录。 RBO 将其转换为 LEFT SEMI JOIN,LEFT SEMI JOIN 只返回左表 (departments) 中在右表 (employees) 中找到匹配行的记录,且对于左表的每一行,右表最多返回一行。 ON 子句中包含了连接条件 d.dept_id = e.dept_id 和子查询的过滤条件 e.salary > 100000。
- 物化 (Materialization) 非相关子查询: 对于某些非相关子查询,RBO 可能会将子查询的结果 物化 为一个临时表。
-- 原始 SQL (非相关子查询多次引用)SELECT (SELECT COUNT(*) FROM orders WHERE status = 'pending') AS pending_orders,(SELECT AVG(total_amount) FROM orders WHERE status = 'completed') AS avg_completed_amount;-- RBO 可能物化子查询结果为临时表 (伪代码)CREATE TEMPORARY TABLE temp_subquery_result ASSELECT 'pending_orders' AS result_name, COUNT(*) AS result_value FROM orders WHERE status = 'pending'UNION ALLSELECT 'avg_completed_amount' AS result_name, AVG(total_amount) AS result_value FROM orders WHERE status = 'completed';SELECT result_value FROM temp_subquery_result WHERE result_name = 'pending_orders';SELECT result_value FROM temp_subquery_result WHERE result_name = 'avg_completed_amount';
机制详解: RBO 检测到两个相同的非相关子查询 (虽然 WHERE 条件不同,但表和基本结构相同)。 为了避免重复计算,RBO 可以将子查询结果预先计算出来,并存储在一个临时表中。 外部查询直接从临时表中获取结果。 注意: MySQL 实际的物化策略比这个伪代码更复杂,会考虑更多因素,例如子查询结果集大小、查询复杂度等
相关子查询 (Correlated Subquery) 的优化 (有限的 RBO 优化)
子查询的执行依赖于外部查询的表。RBO 主要尝试将某些简单的相关子查询 转换为连接。
EXISTS
** 相关子查询转换为**JOIN**
(有限的 Unnesting)😗* 某些简单的EXISTS
相关子查询,RBO 可以尝试转换为JOIN
,例如LEFT SEMI JOIN
。
-- 原始 SQL (简单的 EXISTS 相关子查询)SELECT * FROM customers c WHERE EXISTS (SELECT * FROM orders o WHERE o.customer_id = c.customer_id AND o.order_date >= '2023-01-01');-- RBO 可能转换为 (LEFT SEMI JOIN)SELECT c.* FROM customers cLEFT SEMI JOIN orders o ON o.customer_id = c.customer_id AND o.order_date >= '2023-01-01';
视图合并 (View Merging)
如果查询中使用了视图 (View),RBO 尝试将视图的定义 合并 (Merge) 到主查询中。
-- 假设定义了视图 v_customer_orders
CREATE VIEW v_customer_orders AS
SELECT c.customer_id, c.customer_name, COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;-- 查询视图
SELECT * FROM v_customer_orders WHERE order_count > 5;-- RBO 视图合并后的 SQL (伪代码)
SELECT c.customer_id, c.customer_name, COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name
HAVING order_count > 5; -- 注意这里是 HAVING, 因为原视图有 GROUP BY
条件化简 (Predicate Simplification)
RBO 会尝试化简 WHERE 子句中的条件表达式。
-
常量传递 (Constant Propagation): 将已知常量值代入表达式。
-
死代码消除 (Dead Code Elimination): 移除永远为真或永远为假的条件。
-
布尔代数化简 (Boolean Algebra Simplification): 应用布尔代数规则化简。
-
移除不必要的括号
-
等值传递(equality_propagation)
-
HAVING 子句和 WHERE 子句的合并: 若查询语句中无聚集函数及 GROUP BY 子句
-
常量表检测
外连接消除 (Outer Join Elimination)
在某些情况下,LEFT JOIN
或 RIGHT JOIN
可以被转换为更高效的 INNER JOIN
。
-- 原始 SQL (LEFT JOIN)
SELECT o.*, c.* FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NOT NULL; -- 对 LEFT JOIN 右表列的非 NULL 条件-- RBO 转换为 (INNER JOIN)
SELECT o.*, c.* FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NOT NULL;
其他查询重写规则
例如,DISTINCT
优化、GROUP BY
优化、ORDER BY
优化等。
访问路径选择 (Access Path Selection) - RBO 的早期角色 (现在更多由 CBO 负责)
JOIN 顺序优化 (Join Order Optimization) - RBO 的早期角色 (现在更多由 CBO 负责)
RBO vs. CBO:各有千秋,协同工作
特性 | 基于规则的优化 (RBO) | 基于成本的优化 (CBO) |
优化依据 | 预定义的规则 (启发式规则) | 成本模型 (基于统计信息) |
优化策略 | 查询重写、简单访问路径和 JOIN 顺序选择 | 访问路径选择、JOIN 类型和 JOIN 顺序的精细化选择 (基于成本) |
优化速度 | 快 | 相对较慢 (需要成本估算) |
优化精度 | 相对较低 (依赖规则的有效性) | 较高 (更准确地评估执行计划成本) |
统计信息依赖 | 低 (或不依赖) | 高 (依赖于准确的统计信息) |
适用场景 | 简单查询、快速优化、初步优化 | 复杂查询、精细化优化、对性能要求高的场景 |
在 MySQL 中的角色 | 初步优化、查询重写、为 CBO 优化打基础 | 主要优化器、负责大部分优化决策 |
RBO 的局限性与 CBO 的优势
RBO 虽然速度快,但其优化能力受限于预定义的规则。CBO 基于成本估算,能够更全面地考虑各种因素,做出更明智的优化选择。现代 MySQL 主要依赖 CBO 进行查询优化,RBO 更多地作为辅助手段。
RBO 优化指导与实践建议
-
编写规范的 SQL 语句: 编写符合 RBO 规则的 SQL。
-
理解 MySQL 的 RBO 规则: 了解 MySQL RBO 主要的优化规则。
-
关注
EXPLAIN
** 执行计划:** 使用EXPLAIN
命令分析 SQL 查询的执行计划。 -
结合 CBO 进行优化: RBO 只是优化过程的第一步, 最终性能还是取决于CBO。
子查询优化
子查询语法
按返回结果集区分
-
标量子查询: 只返回一个单一值的子查询。
-
行子查询: 返回一条记录的子查询,包含多个列。
-
列子查询: 返回一个列的数据,包含多条记录。
-
表子查询: 子查询结果既包含多条记录,又包含多个列。
按与外层查询关系区分
-
不相关子查询: 子查询可单独运行出结果,不依赖于外层查询的值。
-
相关子查询: 子查询的执行依赖于外层查询的值。
子查询在布尔表达式中的使用
-
使用
=
、>
、<
等操作符。 -
[NOT] IN/ANY/SOME/ALL
子查询。 -
EXISTS
子查询。
子查询在 MySQL 中的执行方式
-
标量子查询、行子查询的执行方式: 不相关的标量子查询或行子查询,先单独执行子查询,再将结果作为外层查询的参数。相关的标量子查询或行子查询,按外层查询逐条执行。
-
IN 子查询优化:
-
物化表的提出: 对于不相关的 IN 子查询,若子查询结果集较大,优化器会将子查询结果写入临时表(物化表)。
-
物化表转连接: 将子查询物化后,可将外层查询与物化表进行内连接。
-
将子查询转换为 semi-join: 对于符合一定条件的 IN 子查询,优化器会将其转换为 semi-join。
-
semi-join 的适用条件: 子查询必须是和 IN 语句组成的布尔表达式,且在外层查询的 WHERE 或 ON 子句中出现;外层查询可有其他搜索条件,但必须与 IN 子查询的搜索条件使用 AND 连接;子查询必须是单一查询,不能由 UNION 连接;子查询不能包含 GROUP BY、HAVING 或聚集函数等。
-
不适用于 semi-join 的情况: 外层查询的 WHERE 条件中有其他搜索条件与 IN 子查询组成的布尔表达式使用 OR 连接;使用 NOT IN;子查询在 SELECT 子句中;子查询包含 GROUP BY、HAVING 或聚集函数;子查询包含 UNION 等。
-
-
ANY/ALL 子查询优化: 不相关的 ANY/ALL 子查询在很多场合可转换为其他形式执行, 如
< ANY (SELECT inner_expr ...)
可转换为< (SELECT MAX(inner_expr) ...)
。 -
[NOT] EXISTS 子查询的执行: 不相关的 [NOT] EXISTS 子查询,先执行子查询,得出结果后再重写外层查询。相关的 [NOT] EXISTS 子查询,按逐条执行的方式进行。
-
对于派生表的优化: 将子查询放在外层查询的 FROM 子句中,子查询的结果相当于一个派生表。优化器会尝试将派生表与外层查询合并,若无法合并,则将派生表物化为临时表。
实战优化技巧
IN vs EXISTS选择
场景 | 推荐写法 | 原因 |
外层结果集大 | EXISTS | 可快速短路判断 |
内层结果集小 | IN | 物化成本低 |
需要结果去重 | IN + DISTINCT | 利用物化表的自动去重特性 |
派生表优化
-- 原始查询
SELECT * FROM (SELECT dept_id, AVG(salary) avg_sal FROM employees GROUP BY dept_id
) AS dept_sal
WHERE avg_sal > 10000;-- 优化手段:
SET optimizer_switch = 'derived_merge=on'; -- 启用派生表合并
优化验证工具
-- 查看优化器决策过程
SET optimizer_trace="enabled=on";
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
SELECT * FROM information_schema.OPTIMIZER_TRACE;
SET optimizer_trace="enabled=off";
实际使用建议
-
对于关联子查询,确保被驱动表的连接列有索引。
-
大数据集IN查询优先测试物化表性能。
-
使用EXPLAIN FORMAT=JSON分析执行计划细节。
-
定期更新统计信息保证优化器决策准确。
总结
MySQL 基于规则的优化 (RBO) 是查询优化器中不可或缺的一部分。它通过快速的模式匹配和规则应用,对 SQL 查询进行初步的 “整形美容”,提升查询的可读性和执行效率。虽然 RBO 的优化能力相对有限,但它仍然是现代 MySQL 优化器的重要组成部分,与 CBO 协同工作, 共同打造高效的数据库查询引擎。
参考:https://relph1119.github.io/mysql-learning-notes/#/mysql ,推荐理解本文之后去看原书,原书有一定深度需前后贯穿仔细理解
相关文章:
mysql之规则优化器RBO
文章目录 MySQL 基于规则的优化 (RBO):RBO 的核心思想:模式匹配与规则应用RBO 的主要优化规则查询重写 (Query Rewrite) / 查询转换 (Query Transformation)子查询优化 (Subquery Optimization) - RBO 的重中之重非相关子查询 (Non-Correlated Subquery)…...

MySQL数据库——表的约束
1.空属性(null/not null) 两个值:null(默认的)和not null(不为空) 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法…...
vue2.x 中子组件向父组件传递数据主要通过 $emit 方法触发自定义事件方式实现
在 Vue 2.x 中,子组件向父组件传递数据主要通过 自定义事件 的方式实现。具体步骤如下: 1. 子组件通过 $emit 触发事件 子组件可以使用 $emit 方法触发一个自定义事件,并将数据作为参数传递给父组件。 语法: this.$emit(事件名…...

洛谷 P1102 A-B 数对(详解)c++
题目链接:P1102 A-B 数对 - 洛谷 1.题目分析 2.算法原理 解法一:暴力 - 两层for循环 因为这道题需要你在数组中找出来两个数,让这两个数的差等于定值C就可以了,一层for循环枚举A第二层for循环枚举B,求一下看是否等于…...
python用 PythonNet 从 Python 调用 WPF 类库 UI 用XAML
pythonnet 是pythonhe.net通用的神器不多介绍了. 这次这基本上跟python没有关系了. 和winform一样先导包 import clr clr.AddReference("PresentationFramework.Classic, Version3.0.0.0, Cultureneutral, PublicKeyToken31bf3856ad364e35") clr.AddReference(&…...

C++——list模拟实现
目录 前言 一、list的结构 二、默认成员函数 构造函数 析构函数 clear 拷贝构造 赋值重载 swap 三、容量相关 empty size 四、数据访问 front/back 五、普通迭代器 begin/end 六、const迭代器 begin/end 七、插入数据 insert push_back push_front 八、…...
YOLOv11-ultralytics-8.3.67部分代码阅读笔记-utils.py
utils.py ultralytics\data\utils.py 目录 utils.py 1.所需的库和模块 2.def img2label_paths(img_paths): 3.def get_hash(paths): 4.def exif_size(img: Image.Image): 5.def verify_image(args): 6.def verify_image_label(args): 7.def visualize_image_ann…...
Linux 内核 RDMA CM 模块分析:drivers/infiniband/core/cma.c
一、引言 随着高性能计算和大数据处理需求的不断增长,远程直接内存访问(RDMA)技术在数据中心和高性能计算领域得到了广泛应用。RDMA 允许数据直接在不同系统的内存之间传输,而无需经过 CPU 和操作系统的干预,从而显著提高了数据传输效率和系统性能。Linux 内核中的 RDMA …...
Flask flash() 消息示例
目录 安装 Flask 入门:Flask flash() 基本示例 进阶:使用 Flask-WTF Flash 登录结果消息 详解:get_flashed_messages() 详解:flash() 消息的完整生命周期 Flask 提供 flash() 用于向 用户传递临时消息,通常用于: • 表单提交成功或失败 • 用户登录、注册、退出提…...

ImGui 学习笔记(三)—— 隐藏主窗口窗口关闭检测
ImGui 的主窗口是平台窗口,默认是可见的,这会影响视觉效果。那么怎么隐藏 ImGui 的主窗口呢? 这很简单,但是需要针对后端做一些修改。 本文仅介绍在 glfwopengl3 和 win32dx11 两种实现上如何修改。 在 win32dx11 实现上&#…...
ubuntu磁盘清理垃圾文件
大头文件排查 #先查看是否是内存满了,USER 很高即是满了 du -f#抓大头思想,优先删除大文件#查看文件目录 内存占用量并排序,不断文件递归下去 du --max-depth1 -h /home/ -h | sort du --max-depth1 -h /home/big/ -h | sort 缓存文件清理…...

vue-fastapi-admin 部署心得
vue-fastapi-admin 部署心得 这两天需要搭建一个后台管理系统,找来找去 vue-fastapi-admin 这个开源后台管理框架刚好和我的技术栈所契合。于是就浅浅的研究了一下。 主要是记录如何基于原项目提供的Dockerfile进行调整,那项目文件放在容器外部…...

大语言模型微调的公开JSON数据
大语言模型微调的公开JSON数据 以下是一些可用于大语言模型微调的公开JSON数据及地址: EmoLLM数据集 介绍:EmoLLM是一系列能够支持理解用户、帮助用户心理健康辅导链路的心理健康大模型,其开源了数据集、微调方法、训练方法及脚本等。数据集按用处分为general和role-play两种…...
C++STL容器之set
1.介绍 set容器是C标准模板库(STL)中的一个关联容器,用于存储唯一的元素。set中的元素是自动排序的,不允许重复。set通常基于红黑树(一种自平衡二叉查找树)实现,因此插入、删除和查找操作的时间…...

《微软量子芯片:开启量子计算新纪元》:此文为AI自动生成
量子计算的神秘面纱 在科技飞速发展的今天,量子计算作为前沿领域,正逐渐走进大众的视野。它宛如一把神秘的钥匙,有望开启未来科技变革的大门,而微软量子芯片则是这把钥匙上一颗璀璨的明珠。 量子计算,简单来说,是一种遵循量子力学规律调控量子信息单元进行计算的新型计算…...

使用AI创建流程图和图表的 3 种简单方法
你可能已经尝试过使用 LLMs 生成图像,但你有没有想过用它们来创建 流程图和图表?这些可视化工具对于展示流程、工作流和系统架构至关重要。 通常,在在线工具上手动绘制图表可能会耗费大量时间。但你知道吗?你可以使用 LLMs 通过简…...

从波士顿动力到Figure AI:探寻人工智能驱动的机器人智能化
一、引言 1.1 研究背景与意义 在科技飞速发展的当下,机器人智能化已成为全球科技竞争的关键领域,深刻影响着人类社会的生产与生活方式。从工业制造到日常生活服务,从医疗保健到探索未知领域,机器人正逐步渗透进各个行业,展现出巨大的发展潜力与应用价值。其智能化水平的…...
算法——KMP算法(Knuth-Morris-Pratt算法)
KMP算法(Knuth-Morris-Pratt算法)是一种高效的字符串匹配算法,用于在主文本字符串中快速查找模式字符串的出现位置。其核心思想是通过预处理模式字符串,利用部分匹配信息(即“失败函数”或“next数组”)避免…...

一周学会Flask3 Python Web开发-flask3模块化blueprint配置
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们在项目开发的时候,多多少少会划分几个或者几十个业务模块,如果把这些模块的视图方法都写在app.py…...
Pytorch实现之统计全局信息的轻量级EGAN
简介 简介:模型在EGAN的基础上改进了一个降维的自注意力机制,并且设计了一个新颖的选择算子,使用轮盘赌来选择个体,如果他们的适配度满足fchild<VALUE,则被选中的个体将被丢弃。需要在进化的初始阶段尽快找到最佳个体,并在后续阶段保持种群的多样性。 论文题目:LGE…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...