到底能不能用 join

Hive left semi join ,select 和 where中不能出现右表字段/不会生成笛卡尔积 1 left semi join的时间比in的时间短,比in高效 2 left semi join时select中不能出现右表的字段,不然报错 3left semi join 时on中出现左表字段的条件 ,正确;on中出现右表字段的条件 ,正确; 4left semi join 时where中出现左表字段,正确;where中出现右表字段,报错 5Hive 2.0.0-SNAP... 阅读详情

互联网上一直流传着各大公司的 MySQL 军规,其中关于 join 的描述,有些公司不推荐使用 join,而有些公司则规定有条件的使用 join, 它们都是教条式的规定,也没有详细说其中的原因,这就很容出现只知道这么用,但是不知道为什么的情况

那到底能不能使用 join, 什么情况下适合用join,什么情况下不适合用 join, join 有哪些使用原则呢?

本文将详细讲述 join 的执行流程、分析 join 的复杂度,并解答上面的几个常见问题,让读者能详细了解 join 的原理,做到知其然,知其所以然

测试数据准备

为了更好的分析 join 的工作原理,需要准备一些测试数据,我们分别创建 ta 和 tb 两个表,定义 insert_data 函数,然后往 ta 、 tb 表添加测试数据,具体如下所示:

  • 创建测试表
Create Table: CREATE TABLE `ta` (
  `id` int(11) NOT NULL,
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8


Create Table: CREATE TABLE `tb` (
  `id` int(11) NOT NULL,
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  • 定义插入数据函数

定义一个插入数据的函数,用于往 tb 表中插入数据

delimieter ;;

create procedure insert_data()

begin

    declare i int;
    
    set i=1;
    
    while( i <= 1000 ) do
    
        insert into tb values(i,i,i);
        
        set i=i+1;
        
    end while;
    
end;;

delimiter ;

  • 添加测试数据

调用 insert_data 函数 往tb 表 插入1000条数据,tb表前100条数据插入到 ta 表中

mysql> call insert_data();

mysql> insert into ta (select * from tb where tb.a <= 100);

简述

MySQL中join主要用到 Simple nested-loop、 Block nested-loop、Index nested-loop 三种算法,下面针对这几种算法的流程逐一进行分析,在这之前,有几点需要说明下

  1. 本文所有测试都是在 mysql5.7 版本上进行的

  2. 由于mysql会对join的连接方式做优化,为了便于分析 join 的执行过程,文中的 sql 语句 统一使用我们指定的连接方式执行查询,关键字是 straight_join

Simple nested-loop 算法

在 MySQL中执行 select * from ta straight_join tb on ta.a = tb.b; ,语句的 explain 的结果如下:

在这个语句中,ta 是驱动表,tb 是被驱动表,由于表 tb 上 b 字段没有索引,所以针对 tb 表需要走全表扫描

语句的执行流程如下:

  1. 从 ta 表读取一条数据,记为Da
  2. 从 Da 中取出字段 a 去 tb 表查询
  3. 取出 tb 表满足条件的数据,跟 Da数据组合成一行,作为结果集返回
  4. 接着读取 ta 表剩下的数据,重复执行步骤1 到 步骤3,直到读取完 ta 表记录

上面的流程是循环读取 ta 表记录,把每一行记录中的 a字段值, 去 tb 表中查询满足条件的记录,这个过程就类似下面代码中的嵌套for循环

for each row in ta matching range 
{
     for each row in tb matching 
     {
        if row satisfies join conditions, send to client
     }
}
  • 性能分析

每读取一条 ta 表记录,就需要扫描一次 tb 表的记录并与记录中 b 字段的值进行比较

所以总共扫描了 100 * 1000 = 10 万 行记录,进行了 10万次 比较操作

可以看出,总的扫描行数和总比较次数跟 ta 和 tb 表总记录数有关,记录数越大,总扫描行数和比较次数越大

假如 ta 表和 tb 表总记录数 各增加 10 倍,那么,总的扫描行数和比较次数会增加 100 倍,这个效率就非常低下了

基于以上原因,MySQL 没有选择使用 Simple nested-loop 算法了,而是使用了 Block nested-loop 算法

Block nested-loop算法

Block nested-loop 算法对 Simple nested-loop 算法进行了优化,它引入了 join buffer

join buffer 主要用于优化不带索引条件的 join 查询,它会缓存连接 过程中的用到的字段,对于减少扫描次数和比较次数很有帮助

join_buffer_size 参数可以控制 join_buffer 的大小,MySQL 默认的

join_buffer_size 是 256K,可以通过 select @@join_buffer_size

查询目前设置的大小

现以执行 select * from ta straight_join tb on ta.a = tb.b; 语句为例来说说明 Block nested-loop的执行流程

  1. 把 ta 表所有记录读入 join buffer 中,join buffer 只缓存连接过程中必须的数据,这里使用了 select * ,所以,ta 表的记录的所有字段都会放入 join buffer 中

  2. 扫描 tb 表,读取每一行记录,跟 join buffer 中的数据对比,满足条件的数据,将会作为结果集返回

  • 性能分析

整个过程中,读取 ta 表所有记录,读取 tb 表所有记录,相当于 扫描了一遍 ta 表和 tb表,所以扫描总行数是 100 + 1000 = 1100 行

逐行遍历 tb 表,与 join buffer 中的数据比较,由于 join buffer 是无序的,所以,对于 tb 表每一条记录,都需要在 join buffer 中比较 100 次,因此总的比较次数是 1000 * 100 = 10万次

和 Simple nested-loop 比起来,由于有 join buffer 的帮助,Block nested loop 总扫描行数减少了很多,总共扫描了 100 + 1000 = 1100 行

虽然两者总比较次数都是 10 万次,但是,Block nested loop 的比较是在内存中的 join buffer 中进行的,所以,速度上应该会快很多,性能相对也好一些

如果驱动表 ta 数据行数是 M ,被驱动表 tb 数据行数是 N ,总的扫描行数为 M + N , 总的比较次数为 M * N , 所以整个执行过程 近似的复杂度是:M + N + M * N

上述复杂度公式中,M 和 N 调换的话,复杂度不变,所以,这时候选择小表还是大表作为驱动表都一样

join buffer 大小不够用的问题

上面 Block nested loop 执行流程中,第一步是把 整个ta表数据全部读入 join buffer 中,这里由于 ta 表数据少,join buffer 可以放得下全部的数据

如果 join buffer 的大小不足以缓存 ta表所有数据,该怎么办呢?这时候的执行流程又是怎样的呢 ?

答案是:join buffer 分段缓存 ta 表数据,处理完之后,清空缓存,然后再缓存 ta 表剩下的数据

现假设 join buffer 只能放得下 60 行 ta 表记录,执行流程就变成了:

  1. 遍历 ta 表,顺序读取 60 条记录放入 join buffer 中,此时,join buffer 满了

  2. 遍历 tb 表,取出得每一行,跟 join buffer 中得数据比较,组合满足条件得数据,作为结果集返回

  3. 清空 join buffer

  4. 接着上次的位置继续顺序扫描 ta 表,把剩下得 40行数据读入 join buffer 中,紧接着执行第 2 步 到 第 4 步,直到 读取完 ta 表记录

  • 性能分析

由于 ta 表是分两次读入 join buffer 的,所以需要扫描两次 tb 表,所以总扫描行数是 100 + 1000 * 2 = 2100 行

总的比较次数依然保持不变,是:(60 + 40) * 1000 = 10万次

从上面的结果可以看出,join buffer 分段缓存 的性能要比 一次缓存全部驱动表必需数据的方式 要差一些,也就是说,join buffer 分的段数越多,性能相对越差,在驱动表数量行数不变的情况下,分段数的取决于 join_buffer_size 参数的大小,这个参数越大,分段数或越小,反之越大, 所以有些地方建议通过调大 join_buffer_size 参数来提升 join 查询速度的方法,原因也在于此

如果驱动表 ta 数据行数是 M ,被驱动表 tb 数据行数是 N, join buffer 分段数是 K ,则总扫描行数为 M + K * N , 总的比较次数为 M * N , 所以整个执行过程 近似的复杂度是: M + K * N + M * N

显然 K 越小,复杂度越小,性能就越好,K 的最小值是 1 ,也就是 驱动表中所必需的字段能全部缓存到 join buffer 中

而 K 是与 驱动表数据行数 M 和 join_buffer_size 参数相关的,后者通常不会经常变化,所以 M 越小, K 就越小,K 越小,复杂度越小,性能就越好,K 的最小值是 1 ,也就是 驱动表中所必需的字段能全部缓存到 join buffer 中

因此,选择小表作为驱动表,查询性能更好

Index nested-loop算法

分析完上面两种算法,接着来看下 Index nested-loop 算法的执行流程

在 MySQL 中执行 select * from ta straight_join tb on ta.a = tb.a;, 语句的 explain 结果如下:

上述结果中,被驱动表 tb 的字段 a 上有索引,所以,连接的过程中能用上索引,它的执行流程是:

  1. 读取一行 ta 表记录, 记为 Da

  2. 从 Da 中取出 a 字段去 tb 表查询

  3. 读取 tb 表中满足条件的记录,和 Da 组合,作为结果集返回

  4. 重复执行 步骤1 到 步骤 3,直到读取完 ta 表的记录

  • 性能分析

上面的流程是遍历 ta 表,然后从读出的每行记录中取出 a 的值 去 tb 表查询

由于 tb 表的 a 字段上有索引,所以查询 tb 表记录的时候,走的是 B+ 树的查询

我们准备的测试数据中 ta 表 a 字段和tb表 a 字段是一一对应的,因此对于 ta 表的一行记录,在 tb 表中需要做两次 B+ 树查询,一次是普通索引树的查询,一次是回表查询

总的扫描行数是: 100 + 100 = 200 行( tb 表的两次B+树查询是由扫描一次表导致的,所以这里把tb表总扫描次数当作100次)

总的比较次数是: 100 次

如果驱动表 ta 数据行数是 M ,被驱动表 tb 数据行数是 N, 对于驱动表的一行数据,被驱动表需要先查询 a 索引的 B+ 树,再查询主键索引 B+ 树,所以被驱动表查询一行的复杂度是:2 * log2N

总扫描行数为 M + M * 2 * log2N , 总的比较次数为 M , 所以整个执行过程 近似的复杂度是: M + M * 2 * log2N + M = 2 * M * ( 1 + log2N )

近似复杂度公式中,变量是 M 和 N , 很显然,M 对结果影响更大,M 表示的是 驱动表 的数据行数,因此,选择 小表 作为驱动表能显著降低复杂度,提升查询速度

结果分析

上面分析了 Simple nested loop 、 Block nested loop、Index nested loop 这三种算法的执行流程,并详细分析了每种算法的复杂度,根据分析的结果就可以回答本文开头的几个问题了

  • 能不能使用join
  1. 如果能用上被驱动表上的索引,即可以用上 Index nested loop 算法的话,是可以使用 join 的

  2. 如果使用 Block nested loop 算法的话,扫描行数和比较次数比较多,会占用大量的系统资源,特别是对于大表来说,查询速度和系统性能是无法接受的,所以,这种情况下,能不用join就不用join了

如果 explain 结果的 Extra 字段包含 ' Using join buffer (Block Nested Loop) ' 字符串的话,表示使用了 ' Block nested loop ' 算法

  • join 使用原则

在分析 Index nested loop 的复杂度之后,得出一个结论: 选择小表作为驱动表,查询性能更好

对于 Block nested loop 的复杂度分两种情况

  1. join buffer 没有分段, 此时不论选择小表还是大表作为驱动表,复杂度都一样

  2. join buffer 分段了,此时选择小表作为驱动表,复杂度更低,查询性能更好,相比join buffer 没有分段,实际的场景中,join buffer 分段的情况应该更多

综合来讲: 使用 join 应该选择小表 作为驱动表

  • 如何选择 "小" 表

上面 join 使用原则 中讲到选择小表作为驱动表,这里的 小表 并不是指表数据行数少,而是指参与join的表,按照查询条件分别得到结果集,结果集小的表作为驱动表

比如:有以下两个 SQL 语句

语句1:select * from ta straight_join tb on ta.b = tb.b where tb.id <= 20;
语句2:select * from tb straight_join ta on ta.b = tb.b where tb.id <= 20;

ta 表和 tb表么一行数据大小是一样的,语句1 使用 ta 作为驱动表,需要把 ta 表所有行数据(100行)放入 join buffer 中,但是 语句2 使用 tb 作为驱动表,只需要把 tb表前20行数据放入 join buffer, 也即 tb 表只有20行数据参与join, 这么一比较,tb 表查询的结果集更小,所以应该选择数据行数更多但是查询的结果集更小的 tb 表作为驱动表

小结

本文详细讨论了 Simple nested loop 、 Block nested loop、Index nested loop 这三种算法,根据算法的执行流程定量的分析了各个算法的复杂度,再根据复杂度分析了 join 常见的一些问题,更多关于 join 的介绍请参考 MySQL 官网

单细胞转录组肿瘤细胞识别:inferCNV与CopyKAT实战解析 单细胞转录组测序(scRNA-seq)是解析肿瘤微环境的重要技术,但如何从海量细胞中准确区分恶性细胞与正常细胞,始终是数据分析的关键难题。传统marker注释在异质性肿瘤中常失效,而基于拷贝数变异(CNV)的推断方法为这一问题提供了更稳健的解决路径。CNV通过检测染色体大片段的增益或缺失,可在无先验标记的情况下识别恶性细胞,尤其适合实体瘤研究。inferCNV利用染色体滑动窗口分析相对表达量,生成直观的CNV热图;CopyKAT则结合高斯混合模型对每个细胞直接分类,输出肿瘤/正常/非整倍体标签。本文从原理出 阅读详情

相关推荐

解决 Clawdbot 对接 Minimax 出现 401 (Token is unusable) 的问题排查与修复

即便确认 API Key 有效且余额充足,该问题仍可能在 Clawdbot 中持续出现,而在其他工具(如 curl 或 Postman)中测试正常。

hampeter的博客 3075

MySQL | 到底可不可以使用join? | 极客时间

在实际生产中,关于 join 语句使用的问题,一般会集中在以下两类:我们 DBA 不让使用 join,使用 join 有什么问题呢?如果有两个大小不同的表做 join,应...

sinat_27143551的博客 560

基于PCA的故障诊断方法(matlab)

1. PCA原理分析 PCA的原理主要是将原始数据进行降维。其具体工作原理参照:CodingLabs - PCA的数学原理 2. 数据预处理 训练数据集(只有正样本)为维数据,即有n个采样值,每个采样值有m个特征。 2.1 数据归一化 将数据X针对每个特征归一化为均值为0,均方根为1的数据。 其中: 3. PCA降维 3.1 首先求取协方差矩阵 协方差矩阵的公式为: 计算出来的协方差矩阵为特征m*m维矩阵。 3.2 求取特征值和特征向量 求取协方差矩阵R的特征值.

tangxianyu的博客 1万+

不使用left-join等多表关联查询,只用单表查询和Java程序,简便实现“多表查询”效果...

上次我们提到,不使用left-loin关联查询,可能是为了提高效率或者配置缓存,也可以简化一下sql语句的编写。只写单表查询,sql真得太简单了。问题是,查询多个表的数据还是非常需要的。 因此,存在这么一个强烈的需求:查询2个集合,怎么合并2个集合中的数据为1个集合,且数据关联要正确。在实践中,我提炼了如下流程和工具方法:流程 先查询第1个集合,根据第1个集合的结果,查询第2个集合,合并2...

weixin_30332705的博客 1420

思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)

思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)

2301_81256766的博客 1257

Aruba无线控制器实战:如何用Client Match优化企业办公区漫游(附SNR调优技巧)

本文深入解析了如何利用Aruba无线控制器的Client Match功能优化企业办公区无线漫游体验。通过实战配置,详细阐述了基于SNR(信噪比)的精细化调优策略,包括阈值设定、负载均衡与场景化参数调整,旨在解决终端粘滞、乒乓漫游等问题,实现智能、平滑的无缝漫游。

weixin_28318011的博客 228

022:SQL优化--JOIN算法

目录 一. SQL优化--JOIN算法 1.1. JOIN 写法对比 2. JOIN的成本 3. JOIN算法 3.1. simple nested loop join 3.2. index nested loop join 3.3. block n...

weixin_30920091的博客 214

避坑指南:Unity新版InputSystem在移动端的5个常见问题及解决方案

本文针对Unity新版InputSystem在移动端开发中的常见问题,提供了5个关键解决方案,包括虚拟摇杆灵敏度调节、多点触控冲突处理、按钮反馈延迟优化、手势识别与陀螺仪数据融合以及Android/iOS平台差异处理。这些实战经验帮助开发者高效解决触控适配难题,提升移动游戏体验。

soda5的博客 404

在SQL语言中,join什么时候用,什么时候不用啊?请高手举例解释一下。谢谢

JOIN 在内连接时,可以不使用,其它类型连接必须使用。如SELECT * FROM TABLEA INNER JOIN TABLEB ON A.ID=B.ID可以这样写:SELECT * FROM TABLEA,TABLEB WHERE A.ID=B.IDJOIN 有以下几种类型:INNER(内连接)指定返回每对匹配的行。废弃两个表中不匹配的行。如果未指定联接类型,则这是默认设置。FULL(全连...

weixin_33713707的博客 647

Ubuntu上通过FinalShell或Asbru访问CentOS虚拟机

使用FinalShell或Asbru远程连接虚拟机

howard2005的专栏 2279

头歌OpenGauss数据库-G.视图的使用

OpenGauss数据库-G.视图的使用

python一生之敌的博客 1383

到底可不可以使用join?

表t2里插入了1000行数据,在表t1里插入的是100行数据。 select * from t1 straight_join t2 on (t1.a=t2.a); 如果以上语句直接使用join语句,mysql优化器可能会选择表t1或者t2作为驱动表,这会影响我们分析mysql的执行过程。为了方便分析过程中的性能问题,我改用straight_join让mysql使用固定的查询方式执行查询。 可以看到这个表t2上有索引,join过程用上了这个索引,因此这个语句的执行流程是: 1.先从t1表中读取一行数据R。

Drftyytf的博客 1128

36 Agent Memory:如何让智能体记住该记的东西

Agent 会调用工具,只能说明它有了行动能力。要让它跨会话、跨任务持续工作,还需要一套可治理的 Memory 系统。本文讲清上下文窗口、RAG 和 Agent Memory 的区别,以及工作记忆、情景记忆、语义记忆、程序记忆该如何分层设计。

老于的笔记的专栏 89

MySQL JOIN 连接:到底能不能写 JOIN?

文章目录前言一、JOIN连接算法二、OLTP 业务能不能写 JOIN? 前言 很多人下意识地认为 JOIN 会降低 SQL 的性能效率,所以就将一条多表 SQL 拆成单表的一条条查询,但这样反而会影响 SQL 执行的效率。究其原因,在于不了解 JOIN 的实现过程 一、JOIN连接算法 二、OLTP 业务能不能写 JOIN? ..

持之以恒 727

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

python thread join卡住_Python中join不能响应信号的问题

在文章subprocess模块用法中介绍了Python中的threading.Thread.join()时不能响应信号的问题。这个问题被Python官方标记为Bug。Python官方的Issue指出这个Bug与Python的signal、基础线程库thread(C实现)和高级线程库threading(Python封装)都有关,下面首先概览这三个模块的实现,接着通过编译调试的方式来观赏这个Bug的具...

weixin_39918690的博客 3250

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

hql中不能使用union及left join

hql中不能使用union及left join

yflxc的专栏 2544

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

流量一大用SQL是不能用JOIN的

我们当时的场景是,一张销售商品表(SPU维度),一张商品SKU表,和一张活动表,我当时做了三表关联,全部都用到索引的,期初跑的很好,SQL都执行的很快,直到某一天,流量陡增后,连接池里的数据库连接突然突然不够用了,导致所有其他的接口的响应速度都变很慢。并发一来,每个线程都要单独占用一个数据库连接0.2秒了,好了,流量一大,占用大量连接,而之前的连接又没有释放,那故障就马上发生了。后来,我的解决方案是,用单表查询,活动表/商品表/SKU表,各读一次,就再也没有发生过数据库连接不够用了。线程B单表0.01秒。

Sam_Deep_Thinking 321

linux shell join命令一定要把文件先sort,而且不能有空行否则后果很严重

如题

韩王-信 2892

mysql不能先where后join,首先在mysql中发生了什么:join或where

Let's say I have two tables A and B and the following query:select *from Ainner join B on A.id = B.idWhere A.id = 5Does mysql first performs the join or the where?Edit:Cause if for example A contains ...

weixin_39589253的博客 510

mysql能不能多次join_mysql多次join同一张表的处理

在做多表联查的时候有时候会碰到一条sql需要多次查同一张表的情况,比较常见的是主表和码值表的匹配。如主表的多个列都记录了编号信息而非实际内容,需要去码值表去查对应的实际内容,就需要多次join码值表。举个简单的例子,一个班有两个老师,在班的表里记录了两个老师的id,现在要把id换成这两个老师的名字,就需要按照老师的id去查老师表,也就是班级表需要两次join老师表来获取两个老师的名字,如果直接jo...

weixin_39594191的博客 3465

tk-mybatis 不能连接表吗_程序猿被调到"仓库"?当"连接"管理员?之Hive Join 总结...

Hive JoinHive中除了支持和传统数据库中一样的内关联、左关联、右关联、全关联,还支持LEFT SEMI JOIN和CROSS JOIN,但这两种JOIN类型也可以用前面的代替。====具体hive的六种join操作详见《轻松玩转hive中join“六大神兽”之间的关系》====Hive 支持等值连接(a.id = b.id),不支持非等值(a.id>b.id)的连接,因为非等值连接...

weixin_39683176的博客 215

hibernate中不能用left join on的解决办法

 hibernate中不能用left join on的解决办法 hibernate中多表查询时,有时需要用到left join,但是不能用left join on。 也就是说,on这个条件是需要写到hbm配置文件中去的。 比如,汽车和车轮这两个对象,我想做下面的查询,,select 汽车 where 车轮=固特异。 其实这个查询很简单,用left join就能实现。但是需要在汽车的hbm配...

想飞的马 4504

能不能使用join语句?

如果可以使用 Index Nested-Loop Join 算法,也就是说可以用上被驱动表上的索引,其实是没问题的; 如果使用 Block Nested-Loop Join 算法,扫描行数就会过多。尤其是在大表上的 join操作,这样可能要扫描被驱动表很多次,会占用大量的系统资源。所以这种 join 尽量不要用。 所以你在判断要不要使用 join 语句时,就是看 explain 结果里面,Extra 字段里面有没有出现“Block Nested Loop”字样。 在决定哪个表做驱动表的时候,应该是两个表.

qq_34709713的博客 299

35 | 别再说不能使用Join了(这次是优化Join查询-下篇)

1

风雨一更 271

hibernate中为什么select 后面的函数不能有left join时右边的域

hibernate中为什么select 后面的函数不能有left join时右边的域

silentJesse 200

Mysql:到底能不能使用join???

假设被驱动表的行数是M,每次在驱动被驱动表查一行数据,要先搜索索引a,再搜索主键索引。这个过程也是扫描了200行,但共执行了101条语句,比直接join多了100次交互,除此之外,客户端还要自己拼接结果。对驱动表t1做了全表扫描,这个过程需要扫描100行,而对于每一行的R,根据字段a去表t2中查找,在这个语句中,t1是驱动表,t2是被驱动表,t2字段a有索引,join过程中用上了这个索引。两张表t1(a字段有索引,100行数据),t2(a字段有索引,1000行数据)查出表t1的所有数据,有100行。....

关于我是谁 384
上一篇: Linux文件IO操作
下一篇: SpringCloud 2020.0.4 系列之Hystrix看板
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值