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

【SQL技术】不同数据库引擎 SQL 优化方案剖析

一、引言

        在数据处理和分析的世界里,SQL 是不可或缺的工具。不同的数据库系统,如 MySQL、PostgreSQL(PG)、Doris 和 Hive,在架构和性能特点上存在差异,因此针对它们的 SQL 优化策略也各有不同。这些数据库中常见和不常见 SQL 语句的优化方法,涵盖排序、聚合函数、条件查询、分组等操作,同时还会涉及 Hive 和 Doris 中 UDF 函数的优化。

SQL解析器:

二、MySQL 优化策略

存储引擎介绍

  • InnoDB:支持事务、行级锁、外键约束,具有良好的并发性能和数据一致性,是MySQL 5.5及以后版本的默认存储引擎。
  • MyISAM:不支持事务和外键约束,具有较高的插入和查询速度,适用于以读为主的应用场景。
  • Memory:数据存储在内存中,访问速度极快,但数据在服务器重启时会丢失,适用于临时数据存储。
  • Archive:用于存储大量的历史数据,只支持插入和查询操作,不支持更新和删除。
  • CSV:以CSV格式存储数据,适用于数据交换和导入导出。
  • BlackHole:所有写入的数据都会被丢弃,适用于测试和数据过滤。

 

SQL执行流程:

 

(一)条件查询优化

  • 索引使用:确保在经常用于 WHERE 子句的列上创建索引。例如,如果经常根据 user_id 进行查询:
CREATE INDEX idx_user_id ON users (user_id);
  • 避免函数索引:在 WHERE 子句中避免对索引列使用函数,因为这会导致索引失效。例如,以下查询会使索引失效:
SELECT * FROM users WHERE YEAR(created_at) = 2024;

可以改为:

SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';

(二)排序优化

  • 覆盖索引:如果排序的列和查询的列可以使用同一个索引,即覆盖索引,能显著提高排序性能。例如:
CREATE INDEX idx_name_age ON users (name, age);
SELECT name, age FROM users ORDER BY name, age;
  • 控制排序数据量:尽量在 WHERE 子句中过滤掉不必要的数据,减少排序的数据量。

(三)聚合函数优化

  • 分组索引:在 GROUP BY 列上创建索引,有助于提高分组聚合的性能。例如:
CREATE INDEX idx_dept_salary ON employees (department_id, salary);
SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;

三、PostgreSQL 优化策略

存储引擎介绍

  • Heap存储引擎:是PostgreSQL的默认存储引擎,支持MVCC(多版本并发控制),适用于大多数应用场景。
  • B-Tree存储引擎:适用于需要高效的范围查询和排序的场景,如索引和排序操作。
  • Hash存储引擎:适用于需要快速查找的场景,如哈希表和索引。
  • GiST存储引擎:适用于处理几何数据和全文搜索的场景。
  • SP-GiST存储引擎:是GiST的一种变体,适用于处理空间数据的场景。
  • GIN存储引擎:适用于处理数组和JSON数据的场景。
  • BRIN存储引擎:适用于处理大数据集的场景,如数据仓库和日志分析。
  • Bitmap存储引擎:适用于处理位图数据的场景。
  • Partial存储引擎:适用于处理部分索引的场景。
  • Unique存储引擎:适用于处理唯一约束的场景。

SQL执行流程:

(一)条件查询优化

  • 统计信息更新:定期更新表的统计信息,确保查询优化器能够做出更准确的查询计划。使用 ANALYZE 命令:
ANALYZE users;
  • 范围查询优化:对于范围查询,使用 BRIN(块范围索引)可以提高性能。例如:
CREATE INDEX idx_created_at ON users USING BRIN (created_at);

(二)排序优化

  • 并行排序:PostgreSQL 支持并行排序,可以通过调整 max_parallel_workers_per_gather 参数来启用并行排序。
SET max_parallel_workers_per_gather = 4;

(三)聚合函数优化

  • 聚合索引:与 MySQL 类似,在 GROUP BY 列上创建索引可以提高聚合性能。同时,使用 GROUPING SETSROLLUP 和 CUBE 等高级聚合功能时,要确保数据分布均匀。

四、Doris 优化策略

Doris SQL引擎种类

  • Heap存储引擎:是Doris的默认存储引擎,支持MVCC(多版本并发控制),适用于大多数应用场景。
  • B-Tree存储引擎:适用于需要高效的范围查询和排序的场景,如索引和排序操作。
  • Hash存储引擎:适用于需要快速查找的场景,如哈希表和索引。
  • GiST存储引擎:适用于处理几何数据和全文搜索的场景。
  • SP-GiST存储引擎:是GiST的一种变体,适用于处理空间数据的场景。
  • GIN存储引擎:适用于处理数组和JSON数据的场景。
  • BRIN存储引擎:适用于处理大数据集的场景,如数据仓库和日志分析。
  • Bitmap存储引擎:适用于处理位图数据的场景。
  • Partial存储引擎:适用于处理部分索引的场景。
  • Unique存储引擎:适用于处理唯一约束的场景。

SQL执行流程:

(一)条件查询优化

  • 分区和分桶:合理使用分区和分桶可以减少数据扫描量。例如,按日期分区,按用户 ID 分桶:
CREATE TABLE sales (sale_date DATE,user_id INT,amount DECIMAL(10, 2)
)
PARTITION BY RANGE(sale_date) (PARTITION p202401 VALUES LESS THAN ('2024-02-01'),...
)
DISTRIBUTED BY HASH(user_id) BUCKETS 32;
  • 物化视图:对于频繁查询的复杂子查询,可以创建物化视图来提高查询性能。
CREATE MATERIALIZED VIEW mv_sales_summary AS
SELECT sale_date, SUM(amount) FROM sales GROUP BY sale_date;

(二)排序优化

  • 预排序:在创建表时指定预排序键,Doris 会按照预排序键对数据进行排序存储,提高排序查询的性能。
CREATE TABLE orders (order_date DATE,order_id INT,amount DECIMAL(10, 2)
)
ORDER BY order_date;

(三)UDF 函数优化

  • 减少 UDF 调用次数:尽量将 UDF 函数的逻辑合并到 SQL 语句中,减少 UDF 调用的开销。
  • 使用向量化 UDF:Doris 支持向量化 UDF,使用向量化 UDF 可以显著提高计算性能。

五、Hive 优化策略

Hive SQL引擎种类

  • MapReduce引擎:这是Hive最初使用的执行引擎,它将SQL查询转换为一系列的MapReduce任务来执行。这种方式在处理大规模数据时非常有效,但由于MapReduce的启动开销较大,对于小数据量或实时性要求高的查询可能效率较低。
  • Tez引擎:Tez是一种基于有向无环图(DAG)的执行引擎,它可以将多个MapReduce任务组合成一个更高效的执行计划,减少了任务的启动和调度开销,提高了查询性能。Tez特别适合处理复杂的查询和数据挖掘任务。
  • Spark引擎:Spark是一种快速的、通用的大数据处理引擎,它提供了比MapReduce更高效的内存计算能力。Hive可以使用Spark作为执行引擎,通过将SQL查询转换为Spark任务来执行,从而提高查询的执行速度。
  • Flink引擎:Flink是一种流处理和批处理统一的计算引擎,它提供了高效的分布式计算能力和低延迟的处理能力。Hive可以使用Flink作为执行引擎,通过将SQL查询转换为Flink任务来执行,从而提高查询的执行速度和实时性。

SQL执行流程:

(一)条件查询优化

  • 分区裁剪:在 WHERE 子句中使用分区列进行过滤,避免全量数据扫描。例如:
SELECT * FROM logs WHERE dt = '2024-01-01';
  • 谓词下推:启用谓词下推功能,让 Hive 在数据读取阶段就过滤掉不必要的数据。
SET hive.optimize.ppd=true;

(二)排序优化

  • 使用 DISTRIBUTE BY 和 SORT BYDISTRIBUTE BY 用于将数据分发到不同的 reducer,SORT BY 用于在每个 reducer 内部进行排序。例如:
SELECT * FROM sales DISTRIBUTE BY user_id SORT BY amount DESC;

(三)聚合函数优化

  • Map 端聚合:启用 Map 端聚合可以减少数据传输量。
SET hive.map.aggr=true;

(四)UDF 函数优化

  • 缓存中间结果:如果 UDF 函数的计算结果可以复用,在 UDF 内部实现缓存机制,避免重复计算。
  • 使用 Hive 内置函数替代 UDF:优先使用 Hive 内置函数,因为它们经过了优化,性能通常比自定义 UDF 高。

六、SQL调优技巧

(一)慎重使用COUNT(DISTINCT col)

  • 问题原因:在各个数据库中,DISTINCT操作会将所有数据保存在内存中以进行去重操作,在数据量较大时,这可能导致内存溢出(OOM)情况的发生。
  • 解决方案
    • MySQL、PG:考虑使用GROUP BY和COUNT组合来代替COUNT(DISTINCT col)。例如,如果要统计某列的不同值数量,可以通过SELECT col, COUNT(*) FROM table GROUP BY col,然后在应用层进行进一步处理得到去重后的数量。
    • Doris、Hive:除了GROUP BY替代法,还可以使用ROW_NUMBER() OVER(PARTITION BY col)函数。例如在Hive中,SELECT COUNT(*) FROM (SELECT col, ROW_NUMBER() OVER(PARTITION BY col ORDER BY col) AS row_num FROM table) WHERE row_num = 1。这种方式通过窗口函数为每个不同值分配一个序号,然后只计算序号为1的记录数量。

(二)小文件问题

  • 问题原因:小文件会在数据库存储和查询过程中占用过多内存,因为每个小文件都需要一定的元数据管理开销,从而导致查询效率下降。
  • 解决方案
    • Hive
      • 控制小文件产生数量,可以通过调整写入数据时的参数来实现。例如,在使用INSERT语句写入数据时,可以调整mapreduce.output.fileoutputformat.split.maxsizemapreduce.output.fileoutputformat.split.minsize参数,使数据写入更大的文件块中。
      • 使用SequenceFile格式存储数据,这种格式对于小文件处理有较好的优化效果。例如,在创建表时指定STORED AS SEQUENCEFILE
      • 减少Reducer数量,避免动态分区生成过多小文件。可以通过设置hive.exec.reducers.max参数来限制Reducer的最大数量。
    • Doris:在数据导入阶段,可以通过调整导入参数来控制小文件的生成。例如,设置合适的批处理大小,确保每次导入的数据量足够大,避免生成过多小文件。

(三)慎重使用SELECT *

  • 问题原因:查询所有字段意味着数据库需要处理可能存在的无效数据,这无疑是对资源的浪费,特别是在大表查询时,会增加不必要的I/O开销。
  • 解决方案:无论是MySQL、PG还是Doris、Hive(*一般限制数量,不走mr会稍快),都应该指定所需字段名进行查询。例如,将SELECT * FROM table改为SELECT col1, col2, col3 FROM table,只获取实际需要的列数据。

(四)不要在表关联后加WHERE条件

  • 解决方案
    • MySQL、PG、Doris、Hive通用:采用谓词下推技术,将过滤条件尽可能放在表连接之前,提前过滤数据,减少中间结果集的数据量,从而减少数据传输和处理的开销。例如,将SELECT * FROM table1 JOIN table2 ON table1.id = table2.id WHERE table1.col > 10改为SELECT * FROM (SELECT * FROM table1 WHERE table1.col > 10) AS sub_table1 JOIN table2 ON sub_table1.id = table2.id

(五)处理空值数据

  • 问题原因:空值在数据库处理过程中可能会导致一些问题,如在MapReduce过程(特别是在Hive等基于MapReduce架构的数据库中)中的内存不足。
  • 解决方案
    • MySQL、PG:在查询时过滤掉NULL数据,可以使用IS NOT NULLIS NULL条件进行筛选。例如,SELECT col FROM table WHERE col IS NOT NULL
    • Doris、Hive:除了过滤空值,还可以为空值赋随机数(在某些特定场景下,如避免数据倾斜)。在Hive中,可以使用COALESCE函数来处理空值,例如SELECT COALESCE(col, 0) FROM table,这里如果col列为空,则将其替换为0。

(六)设置并行执行任务数

  • 解决方案
    • Hive:通过设置hive.exec.paralleltrue开启并发执行,增加并行度。这在有多个子查询或者多个任务可以同时进行的情况下非常有效,可以提高整体查询效率。

(七)设置合理的Reducer数量

  • 问题原因:过多的Reducer启动会消耗大量的时间和资源,因为每个Reducer都需要初始化和分配资源。
  • 解决方案
    • Hive:根据输入数据量和每个Reducer处理的数据量设置合理的

七、总结

        不同的数据库系统有其独特的架构和性能特点,因此 SQL 优化策略也需要因地制宜。在实际应用中,需要根据具体的业务需求和数据特点,选择合适的优化方法。同时,定期监控数据库的性能指标,不断调整优化策略,才能确保数据库系统始终保持高效稳定的运行。希望本文介绍的优化方案能为你在数据库性能优化方面提供一些有益的参考。

相关文章:

【SQL技术】不同数据库引擎 SQL 优化方案剖析

一、引言 在数据处理和分析的世界里&#xff0c;SQL 是不可或缺的工具。不同的数据库系统&#xff0c;如 MySQL、PostgreSQL&#xff08;PG&#xff09;、Doris 和 Hive&#xff0c;在架构和性能特点上存在差异&#xff0c;因此针对它们的 SQL 优化策略也各有不同。这些数据库中…...

链式结构二叉树(递归暴力美学)

文章目录 1. 链式结构二叉树1.1 二叉树创建 2. 前中后序遍历2.1 遍历规则2.2 代码实现图文理解 3. 结点个数以及高度等二叉树结点个数正确做法&#xff1a; 4. 层序遍历5. 判断是否完全二叉树 1. 链式结构二叉树 完成了顺序结构二叉树的代码实现&#xff0c;可以知道其底层结构…...

使用类别数据编码进行连续变量的特征提取

在数据科学和机器学习中,数据预处理是模型构建的重要步骤。对于处理结构化数据时,特别是包含类别型数据的场景,类别数据编码是必不可少的步骤。类别数据通常以文字、标签等形式出现,但大多数机器学习算法只能处理数值型数据,因此需要将类别数据转化为数值格式。编码方式的…...

PCL 最小包围圆(二维)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 最小包围圆是指能够包含给定点集中所有点的最小圆。这个算法通常用于计算几何、计算机图形学、机器学习等领域。以下是该算法的基本原理和实现流程: 1. 初始化:将点集中的所有点加入待处理列表。 2. 查找最远点:…...

技术文档管理最佳实践:高效、专业、可持续

文章目录 技术文档管理最佳实践&#xff1a;高效、专业、可持续1. 技术文档的核心价值1.1 降低知识流失风险1.2 提升开发效率1.3 增强团队协作1.4 规范技术资产管理 2. 技术文档分类与规范2.1 代码相关文档2.2 过程与运维文档2.3 知识与培训文档 3. 工具选型&#xff1a;自动化…...

56. Uboot移植实验

一、NXP官方Uboot编译与测试 1、将NXP提供的uboot拷贝到ubuntu中。 一个开发板也好运行uboot&#xff0c;DDR或者叫DRAM&#xff0c;串口&#xff0c;SD、EMMC、NAND。板子能工作。 测似结果&#xff1a; 1、uboot能正常启动 2、LCD驱动要根据所使用的屏幕修改。 3、NET初始…...

AI大模型:本地部署deepseek

一、安装lmstudio 1、下载网站&#xff1a; LM Studio - Discover, download, and run local LLMs 2、直接安装即可&#xff0c;记住安装的路径 二、下载deepseek模型 2.1、下载的流程 1、下载网站 https://huggingface.co/models 2、在搜索框输入&#xff1a;deepseek …...

(算法竞赛)图论+DFS深搜——图的dfs遍历1

题目描述 给定一个无向图&#xff0c;包含 n 个顶点&#xff08;编号为 1 到 n&#xff09;和 e 条边。要求从顶点 1 开始进行深度优先搜索&#xff08;DFS&#xff09;&#xff0c;并按照访问顺序输出遍历结果。注意&#xff1a;当存在多个邻接点时&#xff0c;优先访问编号较…...

RK3588平台开发系列讲解(DMA篇)DMA engine使用

文章目录 一、DMA 使用步骤二、DMA接口2.1、DMA 通道管理相关接口2.2、DMA 描述符相关接口2.3、DMA 启动与控制接口2.4、DMA 状态检查接口2.5、 DMA 缓存管理接口2.6、DMA 中断与同步机制沉淀、分享、成长,让自己和他人都能有所收获!😄 Linux 内核的 DMA 引擎提供了一组完整…...

报名 | IEEE ICME 2025 音频编码器能力挑战赛正式开启

音频编码器是多模态大模型的重要组件&#xff0c;优秀的音频编码器在构建多模态系统中至关重要。在此背景下&#xff0c;小米集团、萨里大学、海天瑞声共同主办了 IEEE International Conference on Multimedia & Expo (ICME) 2025 Audio Encoder Capability Challenge。 …...

fputs的概念和使用案例

fputs 是 C 语言中用于向文件写入字符串的标准库函数。它与 puts 类似&#xff0c;但不会自动添加换行符&#xff0c;且支持向任意文件流&#xff08;如磁盘文件、标准输出等&#xff09;写入数据。 概念解析 函数原型&#xff1a;int fputs(const char *str, FILE *stream); …...

ASP.NET Core标识框架Identity

目录 Authentication与Authorization 标识框架&#xff08;Identity&#xff09; Identity框架的使用 初始化 自定义属性 案例一&#xff1a;添加用户、角色 案例二&#xff1a;检查登录用户信息 案例三&#xff1a;实现密码的重置 步骤 Authentication与Authorizatio…...

PFAS(全氟烷基和多氟烷基物质)测试流程详细介绍

PFAS&#xff08;全氟烷基和多氟烷基物质&#xff09;测试详细介绍 什么是PFAS&#xff1f; PFAS是(Per-and polyfluoroalkyl substances)的简称&#xff0c;中文名&#xff1a;全氟烷基和多氟烷基物质&#xff0c;是一系列合成有机氟化物的总称&#xff0c;是指至少含有一个…...

宝塔面板端口转发其它端口至MySQL的3306

最近需要把服务器的MySQL服务开放给外网&#xff0c;但又希望公开给所有人。也不想用默认的3306端口。同时也不想改变MySQL的默认端口。 这时候最好的办法就是用一个不常用的端口来转发至3306上去。例如使用49306至3306&#xff0c;外网通过49306来访问&#xff0c;内网依然使用…...

inquirer介绍及配合lerna在Vue中使用示例

目录 安装基本用法使用多个提示框动态选择&#xff08;动态选项&#xff09;表单式输入配合lerna在Vue中使用示例 Inquirer 是一个用于创建交互式命令行工具的 Node.js 库&#xff0c;常用于收集用户输入。它提供了多种类型的提示框&#xff0c;可以用于创建交互式应用程序&…...

AI商业化:如何包装技术并找到客户需求?

AI商业化:如何包装技术并找到客户需求? 适用人群:对人工智能技术有一定沉淀,正在探索技术变现和商业模式创新的创业者、技术团队以及企业管理者。同时也适合对 AI 产品包装、市场调研与用户调研感兴趣的从业人员。 一、引言 在过去几年里,从 GPT、Transformer 到 DeepSee…...

基于MODIS/Landsat/Sentinel/国产卫星遥感数据与DSSAT作物模型同化的作物产量估算

基于过程的作物生长模拟模型DSSAT是现代农业系统研究的有力工具&#xff0c;可以定量描述作物生长发育和产量形成过程及其与气候因子、土壤环境、品种类型和技术措施之间的关系&#xff0c;为不同条件下作物生长发育及产量预测、栽培管理、环境评价以及未来气候变化评估等提供了…...

OpenAI 宣布免费开放 ChatGPT 搜索,无需注册

在科技飞速发展的今天&#xff0c;人工智能领域的每一次突破都犹如一颗重磅炸弹&#xff0c;震撼着整个世界。北京时间 2025 年 2 月 6 日凌晨&#xff0c;OpenAI 宣布向所有用户开放 ChatGPT 搜索功能&#xff0c;且无需注册&#xff0c;这一消息瞬间引发了全球范围内的广泛关…...

如何打开vscode系统用户全局配置的settings.json

&#x1f4cc; settings.json 的作用 settings.json 是 Visual Studio Code&#xff08;VS Code&#xff09; 的用户配置文件&#xff0c;它存储了 编辑器的个性化设置&#xff0c;包括界面布局、代码格式化、扩展插件、快捷键等&#xff0c;是用户全局配置&#xff08;影响所有…...

DeepSeek-V3本地Docker容器化部署

1. 安装Docker 确保已安装Docker Desktop for Mac&#xff1a; 下载并安装 Docker Desktop。 安装完成后&#xff0c;启动Docker Desktop。 验证安装&#xff1a; docker --version docker-compose --version 2. 克隆DeepSeek-V3仓库 git clone https://github.com/deeps…...

【Leetcode 每日一题】47. 全排列 II

问题背景 给定一个可包含重复数字的序列 n u m s nums nums&#xff0c;按任意顺序 返回所有不重复的全排列。 数据约束 1 ≤ n u m s . l e n g t h ≤ 8 1 \le nums.length \le 8 1≤nums.length≤8 − 10 ≤ n u m s [ i ] ≤ 10 -10 \le nums[i] \le 10 −10≤nums[i]≤…...

【Uniapp-Vue3】从uniCloud中获取数据

需要先获取数据库对象&#xff1a; let db uniCloud.database(); 获取数据库中数据的方法&#xff1a; db.collection("数据表名称").get(); 所以就可以得到下面的这个模板&#xff1a; let 函数名 async () > { let res await db.collection("数据表名称…...

【重生之学习C语言----杨辉三角篇】

目录 ​编辑 --------------------------------------begin---------------------------------------- 一、什么是杨辉三角&#xff1f; 二、问题分析 三、算法设计 使用二维数组存储杨辉三角&#xff1a; 递推关系&#xff1a; 格式化输出&#xff1a; 四、代码实现 完…...

天童教育:帮助孩子建立稳定的自信心

不少家长发现&#xff0c;自己家孩子不知道从什么时候开始&#xff0c;不再自信了。有些孩子在面对挑战时总是畏缩不前&#xff0c;不敢尝试新事物&#xff1b;在众人面前发言时&#xff0c;声音微弱&#xff0c;眼神闪躲。昆明天童教育认为&#xff0c;这些表现往往是孩子自信…...

LabVIEW自定义测量参数怎么设置?

以下通过一个温度采集案例&#xff0c;说明在 LabVIEW 中设置自定义测量参数的具体方法&#xff1a; 案例背景 ​ 假设使用 NI USB-6009 数据采集卡 和 热电偶传感器 监测温度&#xff0c;需自定义以下参数&#xff1a; 采样率&#xff1a;1 kHz 输入量程&#xff1a;0~10 V&a…...

Vim的基础命令

移动光标 H(左) J(上) K(下) L(右) $ 表示移动到光标所在行的行尾&#xff0c; ^ 表示移动到光标所在行的行首的第一个非空白字符。 0 表示移动到光标所在行的行首。 W 光标向前跳转一个单词 w光标向前跳转一个单词 B光标向后跳转一个单词 b光标向后跳转一个单词 G 移动光标到…...

SpringCloud详细讲解

学习目标 微服务框架SpringCloud的核心组件分布式与集群Spring Cloud 优缺点 微服务框架 微服务框架是将某个应用程序开发划分为多个小型服务独立进行业务开发的一种架构模式。以下是对微服务框架的详细介绍&#xff1a; 一、定义与特点 定义&#xff1a;微服务框架围绕业务…...

使用 OpenGL ES 在 iOS 上渲染一个四边形:从基础到实现

使用 OpenGL ES 在 iOS 上渲染一个四边形&#xff1a;从基础到实现 在 iOS 开发中&#xff0c;OpenGL ES 是一个强大的工具&#xff0c;用于实现高性能的 2D 和 3D 图形渲染。本文将详细分析一段完整的代码&#xff0c;展示如何使用 OpenGL ES 在 iOS 上渲染一个简单的四边形。…...

98.2 AI量化开发:基于DeepSeek打造个人专属金融消息面-AI量化分析师(理论+全套Python代码)

目录 0. 承前1. 金融工程结构图2. Why is DeepSeek3. 项目实现代码3.1 导入python库3.2 参数设置3.3 获取数据3.4 数据处理3.5 AI人设提示词3.6 Messages构建3.7 AI Agent3.8 response格式处理3.9 汇总函数3.10 运行案例 4. 总结4.1 系统优点4.2 系统缺点4.3 可提升方向 0. 承前…...

复制粘贴小工具——Ditto

在日常工作中&#xff0c;复制粘贴是常见的操作&#xff0c;但Windows系统自带的剪贴板功能较为有限&#xff0c;只能保存最近一次的复制记录&#xff0c;这对于需要频繁复制粘贴的用户来说不太方便。今天&#xff0c;我们介绍一款开源、免费且功能强大的剪贴板增强工具——Dit…...