PolarDB MySQL 联邦查询优化特征(条件下推、按需返回列、LIMIT OFFSET下推)

news2024/11/24 15:40:00

背景

社区版 MySQL 支持的联邦引擎可以将位于远程数据库实例的表像本地表一样访问,大大方便了用户管理多个数据库实例的数据做聚合查询和分析。但是在性能方面存在着可以优化的地方:

  1. 只有在可以使用索引 RANGE/REF 方式扫描时,可以将索引上的条件作为 SQL 的一部分发送到远程数据库实例,而其他条件都保留在本地数据库执行;
  2. 即使 SQL 只访问了联邦表的一列数据,仍然会拉取远程表的全部列数据到本地;
  3. 带有 LIMIT OFFSET 语法的 SQL,也会拉取全部的数据到本地。

针对这三个问题,PolarDB MySQL 实现了条件下推、按需返回列和 LIMIT OFFSET 下推功能,能够在最大程度的减少无效数据的访问和传输代价,大大提升执行效率。这篇文章会在 PolarDB MySQL 线上环境中,各自模拟这三种场景的查询,测试这些特征对性能的提升情况。

条件下推

条件下推将数据在远程过滤,减少网络 IO 和本地格式转换代价

对于涉及联邦引擎的查询,社区版 MySQL 只有在可以利用索引 RANGE/REF 扫描时,才能将索引上的条件下推,其他的条件保留在本地 server 执行。而实际情况中,一条查询的 WHERE 条件涉及字段可能比较多,或者在索引字段上使用了 function 导致无法直接使用索引,这时联邦引擎会向远程 server 发送全表扫描查询,将所有数据都拉回本地后执行。这种执行方式显然是非常低效的,既导致大量数据的网络传输占用带宽,又带来大量数据在本地进行拷贝、格式转换的代价,通过尽可能将兼容的条件下推,可以使数据在远程就被过滤掉,提升执行性能。

我们使用包含 1 千万条数据的 sysbench 表来模拟在不同选择率条件下,条件下推带来的性能收益,远程和本地 server 均为 4c32G 规格 PSL5 PolarDB MySQL 标准实例,远程表和联邦表定义为:

CREATE TABLE `sbtest1` (
  `id` int NOT NULL,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `idx_1` (`k`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE SERVER s
FOREIGN DATA WRAPPER mysql
OPTIONS (USER 'username', PASSWORD 'password', HOST 'hostname', PORT 3306, DATABASE 'dbname');

CREATE TABLE `sbtest1` (
  `id` int NOT NULL,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `idx_1` (`k`)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='s'

使用如下查询:

local> set optimizer_switch='engine_condition_pushdown=off';
Query OK, 0 rows affected (0.03 sec)

local> EXPLAIN SELECT COUNT(*) FROM sbtest1 WHERE id + 1 < 100;
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | sbtest1 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9850101 |   100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.04 sec)

local> set optimizer_switch='engine_condition_pushdown=on';
Query OK, 0 rows affected (0.10 sec)

local> EXPLAIN SELECT COUNT(*) FROM sbtest1 WHERE id + 1 < 100;
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------------------------------------------------------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra                                                                               |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------------------------------------------------------------------------------+
|  1 | SIMPLE      | sbtest1 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9850101 |   100.00 | Using where with pushed condition ((`federated`.`sbtest1`.`id` + 1) < 100) |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------------------------------------------------------------------------------+
1 row in set, 1 warning (0.05 sec)

由于 WHERE 条件中使用的是包含主键的 function 与常量进行比较,最优执行计划使用的是全表扫描方式。差别在于是否将 WHERE 条件下推到远程执行,通过改变常量值为selectivity * table_size,构造不同的选择率条件,测试性能得到:

可以看到当条件选择率较低(小于0.1)时,有约一倍的性能提升。

通过监控也可以看看测试期间对于网络带宽的占用情况,在测试过程中,条件下推与不下推的查询交替进行,可以看到:

  • 当条件不下推时,对于网络带宽的占用很高,且在不同选择率条件下都是相同的;
  • 当条件下推且选择率较低(小于0.1)时,网络的流量非常小,随着选择率的增大逐渐增多,和条件不下推的网络 IO 相比有明显区别。

条件下推给远程 server 更多的执行计划选择,带来更优的计划

涉及联邦引擎的查询在寻找最优执行计划时,本地的统计数据非常有限,是临时向远程 server 发送SHOW TABLE STATUS LIKE 'table_name'命令获取的,返回的结果里只有表一共多少行的估算是可用的。索引上的统计信息完全缺失,因此在涉及索引选择时会出现非常大的代价偏差,下面的例子可以说明:

沿用上节的表定义,远程表中包含 1 千万条数据,k 也从 1 到 1 千万均匀随机分布。当使用如下查询时,不论 WHERE 条件的值为什么,优化器都会默认选择联邦表的主键 RANGE 扫描方式,因为优化器不具备根据值来估算代价的能力:

local> EXPLAIN SELECT COUNT(*) FROM federated.sbtest1 WHERE id < 10000000 AND k BETWEEN 9000000 AND 9000100;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | sbtest1 | NULL       | range | PRIMARY,idx_1 | PRIMARY | 4       | NULL |    2 |     2.50 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
# WHERE 条件是 id < 10000000 AND k BETWEEN 9000000 AND 9000100 时,trace 输出:
                    "range_scan_alternatives": [
                      {
                        "index": "PRIMARY",
                        "ranges": [
                          "id < 10000000"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "in_memory": -1,
                        "rows": 2,
                        "cost": 1.31,
                        "chosen": true
                      },
                      {
                        "index": "idx_1",
                        "ranges": [
                          "9000000 <= k <= 9000100"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "in_memory": -1,
                        "rows": 2,
                        "cost": 1.31,
                        "chosen": false,
                        "cause": "cost"
                      }
                    ]

# WHERE 条件是 id < 10 AND k BETWEEN 9000000 AND 9000100 时
                    "range_scan_alternatives": [
                      {
                        "index": "PRIMARY",
                        "ranges": [
                          "id < 10"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "in_memory": -1,
                        "rows": 2,
                        "cost": 1.31,
                        "chosen": true
                      },
                      {
                        "index": "idx_1",
                        "ranges": [
                          "9000000 <= k <= 9000100"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "in_memory": -1,
                        "rows": 2,
                        "cost": 1.31,
                        "chosen": false,
                        "cause": "cost"
                      }
                    ]

从上面 optimizer trace 在不同条件下的输出可以看到,代价的评估结果都是相同、根据默认值生成的。由于用到主键索引,MySQL 社区版会将主键上的条件下推,其他条件保留,所以这条查询实际发往到远程表的 SQL 为:

remote> EXPLAIN SELECT id, k, c, pad FROM sbtest1 WHERE id < 10000000;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | sbtest1 | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL | 4925050 |   100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

造成主键扫描返回大量的数据。而如果我们将字段 k 上的条件也下推,会给远程优化器更多的索引选择空间,而且在远程 server 上是有索引上的统计信息,也可以 index dive 去根据具体值估算代价,得到更优的执行计划:

remote> EXPLAIN SELECT id, k, c, pad FROM sbtest1 WHERE id < 10000000 AND k BETWEEN 9000000 AND 9000100;
+----+-------------+---------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | sbtest1 | NULL       | range | PRIMARY,idx_1 | idx_1 | 4       | NULL |   92 |    50.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

所以开启下推所有条件,可以带来性能的大幅提升:

local> set optimizer_switch='engine_condition_pushdown=off';
Query OK, 0 rows affected (0.00 sec)

local> SELECT COUNT(*) FROM federated.sbtest1 WHERE id < 10000000 AND k BETWEEN 9000000 AND 9000100;
+----------+
| COUNT(*) |
+----------+
|       94 |
+----------+
1 row in set (8.49 sec)

local> set optimizer_switch='engine_condition_pushdown=on';
Query OK, 0 rows affected (0.00 sec)

local> SELECT COUNT(*) FROM federated.sbtest1 WHERE id < 10000000 AND k BETWEEN 9000000 AND 9000100;
+----------+
| COUNT(*) |
+----------+
|       94 |
+----------+
1 row in set (0.00 sec)

按需返回列

联邦查询在获取远程表的数据时,返回的是所有列的值;但实际情况中,一条查询可能只需要部分列的值,其他列的值并没有发挥作用,反而增加了远程服务器选取、格式转换的代价,增加了网络传输数据量,占用带宽。因此 PolarDB MySQL 在社区版 MySQL 的基础上做了进一步优化,使得联邦查询只会向远程 server 选取需要的列,大幅减少了远程 server 选取的代价和网络 IO,提升了查询性能,表的列数越多,效果越明显。

下面使用包含 1 百万数据,不同列数的表来模拟真实场景。包含 100 列的表定义如下,重复定义 sysbench 表中 k、c、pad 三列来拓宽表;减少字符类型的长度来支持定义更多列,而不至于空间占用非常剧烈,500 列的空间占用约为 5 GB,可以完全缓存在 Buffer Pool 中。

CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(15) NOT NULL DEFAULT '',
  `pad` char(8) NOT NULL DEFAULT '',
  `k1` int(11) NOT NULL DEFAULT '0',
  `c1` char(15) NOT NULL DEFAULT '',
  `pad1` char(8) NOT NULL DEFAULT '',
  ...
  `k32` int(11) NOT NULL DEFAULT '0',
  `c32` char(15) NOT NULL DEFAULT '',
  `pad32` char(8) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8

使用查询SELECT pad FROM sbtest1分别在按需返回列开启和不开启状态下进行测试,由于远程表在 pad 字段上没有索引,所以执行计划都是主键全表扫描,结果如下:

表列数48163264128256512
按需返回列(s)2.973.13.093.964.554.955.746.91
返回全表(s)3.143.334.126.058.812.620.338.7

从加速比曲线可以看出,随着表列数的增加,按需返回列特征带来的加速比接近线性提升。

在测试过程中对网络 IO 的占用减少效果也非常明显:

此外,按需返回列特征也会增加远程 server 的计划选择空间,如果查询所访问的列可以用到索引,那么会在远程表使用索引扫描,而不是全表扫描,这会带来巨大的性能提升:

mysql> SET federated_fetch_select_field_enabled=OFF;
Query OK, 0 rows affected (0.19 sec)

mysql> SELECT SUM(k) FROM federated_col_64.sbtest1;
+--------------+
| SUM(k)       |
+--------------+
| 499868973740 |
+--------------+
1 row in set (5.20 sec)

mysql> SET federated_fetch_select_field_enabled=ON;
Query OK, 0 rows affected (0.11 sec)

mysql> SELECT SUM(k) FROM federated_col_64.sbtest1;
+--------------+
| SUM(k)       |
+--------------+
| 499868973740 |
+--------------+
1 row in set (0.45 sec)

LIMIT OFFSET 下推

社区版 MySQL 在联邦查询上的分页查询由于无法将条件全下推,所以必须将全部数据拉回本地,使用 WHERE 条件过滤后再进行分页。当 PolarDB MySQL 实现条件下推后,如果语句只涉及单个联邦表,且不包含聚合、窗口、UNION、DISTINCT、ORDER BY、HAVING 等影响结果正确性的语法时,就可以将 LIMIT OFFSET 语法下推到远程 server,仅返回需要的数据,本地 server 可以直接输出结果到客户端。使用效果如下:

local> set optimizer_switch='limit_offset_pushdown=on';
Query OK, 0 rows affected (0.05 sec)

local> EXPLAIN SELECT * FROM federated.sbtest1 LIMIT 100 OFFSET 1000;
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-----------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra                       |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-----------------------------+
|  1 | SIMPLE      | sbtest1 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9850101 |   100.00 | Using limit-offset pushdown |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-----------------------------+
1 row in set, 1 warning (0.06 sec)

local> set optimizer_switch='limit_offset_pushdown=off';
Query OK, 0 rows affected (0.05 sec)

local> EXPLAIN SELECT * FROM federated.sbtest1 LIMIT 100 OFFSET 1000;
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------+
|  1 | SIMPLE      | sbtest1 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9850101 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.05 sec)

在 1 千万条数据的 sysbench 表上,使用LIMIT 100 OFFSET ?测试不同的 OFFSET 值:

OFFSET 值010100100010000100000100000010000000
LIMIT OFFSET 下推110 ms168 ms238 ms280 ms219 ms184 ms320 ms1.16 s
未下推6.7 s6.6 s6.68 s6.66 s6.69 s6.77 s6.94 s9.87 s

OFFSET 值越小,效果越明显,最高约 60x 加速比。

总结

条件下推和按需返回列可以将不需要的数据和多余列在远程数据库就被过滤掉,对于过滤性强的条件和宽表有显著的性能效果,也减少了网络资源的带宽占用。同时可以给远程数据库更大的计划选择空间,更优的计划往往意味着查询性能巨大的提升。

LIMIT OFFSET 下推可以在分页查询场景仅查询需要的数据,加速效果非常明显。

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

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

相关文章

2.21 alarm函数 2.22setitimer定时器函数

2.21 alarm函数 #include <unistd.h> unsigned int alarm(unsigned int seconds);功能&#xff1a;设置定时器&#xff08;闹钟&#xff09;。函数调用&#xff0c;开始倒计时&#xff0c;当倒计时为0的时候&#xff0c; 函数会给当前的进程发送一个信号&#xff1a;SIG…

chatgpt赋能python:Python如何另起一行输出

Python如何另起一行输出 如果你正在学习Python编程&#xff0c;你肯定已经遇到过这个问题&#xff1a;如何另起一行输出&#xff1f; Python是一门非常强大的编程语言&#xff0c;它可以完成各种各样的任务&#xff0c;包括从简单的文本处理到复杂的数据分析和机器学习。但是…

【Paper】2019_Event-triggered based scaled consensus for multi-agent systems

Wu X, Mu X. Event-triggered based scaled consensus for multi-agent systems[C]//2019 Chinese Control Conference (CCC). IEEE, 2019: 5544-5549. 文章目录 1 Introduction2 Preparation and problem description2.1 Graph theory2.2 Problem formulation 3 Centralized a…

chatgpt赋能python:Python怎么变颜色

Python怎么变颜色 Python是一种高级编程语言&#xff0c;因其简单易学、开发效率高、运行速度快等优点而广受开发者欢迎。在Python编程过程中&#xff0c;经常需要输出不同颜色的文字以便于提示用户。那么&#xff0c;Python怎么变颜色呢&#xff1f;本文将为大家介绍Python中…

小型中文版聊天机器人

入门小菜鸟&#xff0c;希望像做笔记记录自己学的东西&#xff0c;也希望能帮助到同样入门的人&#xff0c;更希望大佬们帮忙纠错啦~侵权立删。 目录 一、简单介绍与参考鸣谢 二、数据集介绍 三、数据预处理 1、重复标点符号表达 2、英文标点符号变为中文标点符号 3、繁…

visionpro与abb机器人通信

视觉把坐标传给机器人&#xff0c;机器人根据坐标去拿料 接线&#xff1a;用的海康的镜头 机器人是PNP输出 海康接个1千欧的电阻 接的机器人db652板14和15口子 VP设置 作为 服务器 abb位客户端 发往abb的xy坐标 通信成功会如下图所示 ABB需要的配置项 ABB多任务走通信把…

chatgpt赋能python:Python如何取消空格提升SEO排名

Python如何取消空格提升SEO排名 作为一种高效的编程语言&#xff0c;Python已经成为了许多网站开发人员和SEO优化人员的首选工具。在网站优化中&#xff0c;取消空格是一个重要的优化技术&#xff0c;它可以提升网站速度&#xff0c;提高网站体验&#xff0c;同时也可以提升SE…

关于使用keil瑞萨A4M2踩过的坑

一、之前在rasc添加的组件不能删除。 下面在rasc添加ThreadX&#xff0c;不只是RTOS&#xff0c;其他组件也出现这种情况。 当去掉组件不使用&#xff0c;重新配置。但是组件还是显示在软件包&#xff0c;导致编译出错。 解决方式&#xff0c;自己琢磨发现&#xff1a; 找到工…

经典多模态模型

整点传统多模态学习 接下来看看经典模型&#xff0c;传统多模态任务是下游任务是图文检索(Image Text Retrieval)&#xff0c;视觉问答&#xff08;VQA&#xff09;&#xff0c;视觉推理&#xff08;Visual Reasoning&#xff09;&#xff0c;视觉蕴含&#xff08;Visual Enta…

总结897

每周小结&#xff1a; 这周将线代强化进行到第3讲&#xff0c;做杨超三大计算 英语每天早上巩固之前背诵的文章&#xff0c;每日一个长难句分析&#xff0c;背单词&#xff0c;做题目&#xff0c;准备六级 专业课&#xff0c;刚开始复习 每日必复习&#xff08;5分钟&#x…

【C/C++数据结构与算法】华为C/C++编程规范

目录 一、文件结构 二、程序版式 三、命名规则 四、表达式与基本语句 五、常量 六、函数设计 七、内存管理 八、C高级特性 一、文件结构 避免头文件被重复引用&#xff0c;用 #pragma once 进行预处理用 <> 引用标注库头文件&#xff0c;用 "" 引用自…

Servlet图书管理系统测试报告

密级 中级 (供内部测试完毕后使用) Servlet图书管理系统 测试报告 报告编号: ServletBMS-TR-1 &#xff08;Servlet Book Management System-Testing Report&#xff09; 部门经理______项目经理______ 开发经理______测试经理______ 研发公司: 第六科技有限公司 用户单…

【Web服用应用】LVS+Keepalived群集

LVSKeepaLived群集 一、Keepalived及其工作原理1.1Keepalived体系主要模块及其作用1.2健康检查的方式&#xff08;探针&#xff09; 二、LVSKeepalived 高可用群集部署2.1LVS部署<font colorred>1.配置负载调度器&#xff08;主、备相同&#xff09;2配置节点服务器 三、…

JS逆向吐环境

这里调用时机是webpack加载器加载完成后的吐出 1.定位加载器 2.断下目标模块 1.加载完成后&#xff0c;sfu(t), 可以看到明显的加载器&#xff0c;手扣太费劲&#xff0c;直接输出吧 可以看到明显的模块函数&#xff0c;随便测试一个 把函数转为字符串&#xff0c;调用的函数环…

chatgpt赋能python:Python中的矩阵合并方法:介绍和使用方法

Python中的矩阵合并方法: 介绍和使用方法 矩阵合并是Python编程中常用的操作之一&#xff0c;特别是针对数据分析、机器学习和深度学习等领域。Python提供了多种方法来合并矩阵&#xff0c;本文将介绍这些方法并分享如何在实际应用中使用它们。 普通矩阵合并 最基础的矩阵合…

前端vue入门(纯代码)06

【04.mixin混入】 功能&#xff1a;可以把多个组件共用的配置提取成一个混入对象 使用方式&#xff1a; 第一步&#xff1a;定义混合并暴露。 export const mixin {data(){....},methods:{....}.... }第二步&#xff1a;导入mixin.js【混入】文件&#xff0c;并使用混入。 全局…

动态规划dp —— 20.环形子数组的最大和

因为数组是环形的&#xff0c;所以子数组最大和有两种情况&#xff1a; 一个数组内所以数的和是固定的&#xff0c;如果阴影部分是最大子数组和&#xff0c;那么空白部分就是最小子数组和&#xff0c;因此&#xff1a;第二种情况下&#xff0c;只需要求得最小子数组和&#xff…

Java虚拟机——垃圾收集算法

垃圾收集算法的实现涉及大量的程序细节。这里只重点介绍 分代收集理论 和 几种算法思想及发展过程 3.3.1 分代收集理论 分代收集建立在两个 分代假说之上 弱分代假说 &#xff1a; 绝大多数对象都是朝生夕灭的强分代假说&#xff1a; 熬过越多次垃圾收集过程的对象就越难以…

chatgpt赋能python:Python与数据库连接的完整指南

Python与数据库连接的完整指南 作为全球最受欢迎的编程语言之一&#xff0c;Python已经被广泛应用于各种领域&#xff0c;特别是与数据库的交互。 Python拥有用于连接各种数据库的强大库和API&#xff0c;其中包括MySQL&#xff0c;Oracle&#xff0c;PostgreSQL等。在这里&am…

远程控制和原理和实践

按理来说&#xff0c;本人不该发表此类专业的文章&#xff0c;但是从鄙人的开发经历出发&#xff0c;让本人斗胆在此对远控软件做一些论述&#xff0c;谈论一点自己的认识。 程序工程代码地址&#xff1a;点击此处下载。 程序分为两个部分&#xff0c;控制端和被控端&#xf…