Hive相关操作总结

一. 打开Hive

1.1 beeline方式

beeline -u "jdbc:hive2://${hive_server2_host}:${hive_server2_port}" -n $HADOOP_USER_NAME -f $job

命令行方式:
[david_admin@server111-111-22-11 ~]$ beeline
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
WARNING: Use "yarn jar" to launch YARN applications.
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/jars/log4j-slf4j-impl-2.8.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/jars/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Beeline version 2.1.1-cdh6.1.0 by Apache Hive

beeline> !connect jdbc:hive2://111.111.22.11:10000 -n deploy_man
Connecting to jdbc:hive2://111.111.22.11:10000
Connected to: Apache Hive (version 2.1.1-cdh6.1.0)
Driver: Hive JDBC (version 2.1.1-cdh6.1.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://111.111.22.11:10000> 

0: jdbc:hive2://111.111.22.11:10000> select * from app_visit_info;
INFO  : Compiling command(queryId=hive_20200323163246_979dec7e-a598-4bea-8f65-af1517da0903): select * from app_visit_info
INFO  : Semantic Analysis Completed
INFO  : Returning Hive schema: Schema(fieldSchemas:[FieldSchema(name:app_visit_info.uid, type:string, comment:null), FieldSchema(name:app_visit_info.appname, type:string, comment:null), FieldSchema(name:app_visit_info.visit_cnt, type:bigint, comment:null), FieldSchema(name:app_visit_info.visit_day, type:string, comment:null)], properties:null)
INFO  : Completed compiling command(queryId=hive_20200323163246_979dec7e-a598-4bea-8f65-af1517da0903); Time taken: 0.583 seconds
INFO  : Executing command(queryId=hive_20200323163246_979dec7e-a598-4bea-8f65-af1517da0903): select * from app_visit_info
INFO  : Completed executing command(queryId=hive_20200323163246_979dec7e-a598-4bea-8f65-af1517da0903); Time taken: 0.0 seconds
INFO  : OK
+---------------------+-------------------------+---------------------------+---------------------------+
| app_visit_info.uid  | app_visit_info.appname  | app_visit_info.visit_cnt  | app_visit_info.visit_day  |
+---------------------+-------------------------+---------------------------+---------------------------+
| 1                   | 豆瓣                      | 1                         | 20180507                  |
| 1                   | 喜马拉雅                    | 2                         | 20180507                  |
| 1                   | 知乎                      | 3                         | 20180507                  |
| 1                   | 网易云音乐                   | 4                         | 20180507                  |
| 1                   | 京东                      | 5                         | 20180507                  |
| 1                   | 拼多多                     | 6                         | 20180507                  |
| 1                   | 网易云课堂                   | 7                         | 20180507                  |
| 2                   | 豆瓣                      | 7                         | 20180507                  |
| 2                   | 喜马拉雅                    | 6                         | 20180507                  |
| 1                   | 网易云音乐                   | 5                         | 20180508                  |
| 1                   | 京东                      | 4                         | 20180508                  |
| 1                   | 拼多多                     | 2                         | 20180508                  |
| 1                   | 网易云课堂                   | 6                         | 20180508                  |
| 1                   | 中国mooc                  | 15                        | 20180508                  |
+---------------------+-------------------------+---------------------------+---------------------------+
43 rows selected (0.786 seconds)


脚本使用方式:
[david_admin@server111-111-22-11 ~]$ beeline -u "jdbc:hive2://111.111.22.11:10000" -n deploy_man -f test.sql 
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
WARNING: Use "yarn jar" to launch YARN applications.
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/jars/log4j-slf4j-impl-2.8.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/jars/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Connecting to jdbc:hive2://111.111.22.11:10000
Connected to: Apache Hive (version 2.1.1-cdh6.1.0)
Driver: Hive JDBC (version 2.1.1-cdh6.1.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://111.111.22.11:10000> select 'Start testing....';
INFO  : Compiling command(queryId=hive_20200323162006_6f713abe-5209-4d0f-ab91-d9e64af714c7): select 'Start testing....'
INFO  : Semantic Analysis Completed
INFO  : Returning Hive schema: Schema(fieldSchemas:[FieldSchema(name:_c0, type:string, comment:null)], properties:null)
INFO  : Completed compiling command(queryId=hive_20200323162006_6f713abe-5209-4d0f-ab91-d9e64af714c7); Time taken: 0.371 seconds
INFO  : Executing command(queryId=hive_20200323162006_6f713abe-5209-4d0f-ab91-d9e64af714c7): select 'Start testing....'
INFO  : Completed executing command(queryId=hive_20200323162006_6f713abe-5209-4d0f-ab91-d9e64af714c7); Time taken: 0.001 seconds
INFO  : OK
+--------------------+
|        _c0         |
+--------------------+
| Start testing....  |
+--------------------+
1 row selected (0.496 seconds)

1.1 hive命令行方式打开hiveserver2 thrift服务

nohup ${HIVE_BIN_PATH}/hive --service hiveserver2  &

二. 导入数据

我们在hive的使用过程中, 一般第一步需将待分析数据进行导入.一般有4种导入方式, 不同的导入方式在效率上也不一样.
- 从本地文件系统中导入
- 从HDFS中导入
- 从其他Hive表中导入
- 建表的同时,导入数据

从本地文件系统中导入

①.建表
create table if not exists load_data_local_test(
id int,
name string)
row format delimited
fields terminated by '\u0001 ’
lines terminated by ‘\n’;
.
②. 导入本地数据
load data local inpath ‘/home/cdh610/hive_test/load_data_local_test.txt’ into table load_data_local;
注意:
本地系统导入数据大Hive表中时,本地文件的路径必须使用绝对路径.
数据导入验证:
1: select * from default.load_data_local_test;
2: hadoop fs -ls /dw/default/load_data_local_test;

从HDFS中导入

①.建表
create table if not exists load_data_hdfs_test(
id int,
name string)
row format delimited
fields terminated by '\u0001 ’
lines terminated by ‘\n’;
.
②. 本地创建load_data_hdfs_test.txt,并导入到hdfs中: hadoop fs -put ./load_data_hdfs.txt /dw
.
③. 导入本地数据
load data inpath ‘/dw/load_data_hdfs_test.txt’ into table load_data_hdfs_test;
注意:
从hdfs文件系统导入数据成功后,会把hdfs文件系统中原位置的load_data_hdfs.txt文件删除掉.
数据导入验证:
1: select * from default.load_data_hdfs_test;
2: hadoop fs -ls /dw/default/load_data_hdfs_test;

从其他Hive表中导入

①.导入的前提
源表 和 目标表 都已经存在.
②.创建目标表
create table if not exists load_data_from_other_hive_table_test(
id int,
name string)
row format delimited
fields terminated by '\u0001 ’
lines terminated by ‘\n’;
.
③. 导入本地数据
insert into table load_data_from_other_hive_table_test select * from load_data_hdfs_test;

建表的同时,导入数据

这种方式的创建表的表结构来自于select查询语句的查询字段。
create table load_data_from_select_other_hive_table_test as select * from load_data_hdfs_test;

三. Hive 优化

3.1JOIN优化

Join查找操作的基本原则:应该将条目少的表/子查询放在 Join 操作符的左边。原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生内存溢出错误的几率。

①. 多表JOIN与MR生成个数的关系?

Join查找操作中如果存在多个join,且所有参与join的表中其参与join的key都相同,则会将所有的join合并到一个mapred程序中。

-- 在一个mapre程序中执行join (根据如上原理, 因表a,b,c 在join关联时,使用了相同的key字段)
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1);  

-- 在两个mapre程序中执行join (根据如上原理, 因表a,b,c 在join关联时, b与a使用了key1字段; b与c使用了key2字段关联).
-- 可以以["学生", "选课","课程"]这3个经典的表作为类比, 选课表与学生通过student_id进行关联, 而与课程表 通过course_id进行关联.
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2);  

②、大小表join问题

1、小表join大表,小表在前(left join, right join相反)
在两个表进行连接时,用小表来驱动大表可以提高系统的执行效率。
两表连接时,先执行的是两个表的笛卡尔积,接着是 on 的条件筛选,然后是 join 类型进行外部行的添加。
如果是 inner join,没有什么差别;
如果是 left join,就应该把大表放在后面;
如果是 right join,就应该把大表放在前面。
2、map side  join
map-side join 是一种特殊类型的join。如果join 有一个较小的表 ,这个小表可以加载到in-memory构成hash map,直接在map/reduce 过程中的map阶段完成join

明确指定 mapjoin  : 
select  /*+ MAPJOIN(b) */  a.xx ,b.xx  
from a join b on a.xx = b.xx
(相当于指定表b(小表)为缓存表)
备注:1. 如果join 是 full / right outer  join类型  就不能使用 map-side了,因为左右两个表都需要被streamed.

和map join相关的Hive参数为:
- hive.join.emit.interval  
- hive.mapjoin.size.key  
- hive.mapjoin.cache.numrows

③、join操作中的where和on条件执行顺序与效率问题?

由于join操作是在where操作之前执行,所以当你在执行join时,where条件并不能起到减少join数据的作用.

对于带WHERE条件的JOIN语句,例如:
执行顺序是,首先完成2表JOIN,然后再通过WHERE条件进行过滤,这样在JOIN过程中可能会输出大量结果,再对这些结果进行过滤,比较耗时。
左连接时,左表中出现的JOIN字段都保留,右表没有连接上的都为空。
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'

可以进行优化,将WHERE条件放在ON里面,例如:
SELECT a.val, b.val FROM a LEFT OUTER JOIN b
ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07')

这样,在JOIN的过程中,就对不满足条件的记录进行了预先过滤,可能会有更好的表现。

④、关于表stream化?
在join操作的每一个mapred程序中,hive都会把出现在join语句中相对靠后的表的数据stream化,相对靠前的变的数据缓存在内存中。

当然,也可以手动指定stream化的表:

SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

3.2 Group by 优化

Map端聚合,首先在map端进行初步聚合,最后在reduce端得出最终结果,相关参数:

  • hive.map.aggr = true (是否在 Map 端进行聚合,默认为 True)
  • hive.groupby.mapaggr.checkinterval = 100000 (在 Map 端进行聚合操作的条目数目)

数据倾斜聚合优化,设置参数hive.groupby.skewindata = true,当选项设定为 true,生成的查询计划会有两个 MR Job。
第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;
第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。

3.3 合并小文件

文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响:

  • hive.merge.mapfiles = true (是否和并 Map 输出文件,默认为 True)
  • hive.merge.mapredfiles = false (是否合并 Reduce 输出文件,默认为 False)
  • hive.merge.size.per.task = 256*1000*1000 (合并文件的大小)

3.4 Hive实现(not) in

通过left outer join进行查询,(假设B表中包含另外的一个字段 key1
select a.key from a left outer join b on a.key=b.key where b.key1 is null
通过left semi join 实现 in
SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key)
Left semi join 的限制:join条件中右边的表只能出现在join条件中。

3.5 排序优化

Order by 实现全局排序,一个reduce实现,效率低
Sort by 实现部分有序,单个reduce输出的结果是有序的,效率高,通常和DISTRIBUTE BY关键字一起使用(DISTRIBUTE BY关键字 可以指定map 到 reduce端的分发key)
CLUSTER BY col1 等价于DISTRIBUTE BY col1 SORT BY col1

3.6 使用分区

Hive中的每个分区都对应hdfs上的一个目录,分区列也不是表中的一个实际的字段,而是一个或者多个伪列,在表的数据文件中实际上并不保存分区列的信息与数据。Partition关键字中排在前面的为主分区(只有一个),后面的为副分区
静态分区:静态分区在加载数据和使用时都需要在sql语句中指定
案例:(stat_date=‘20120625’,province=‘hunan’)
动态分区:使用动态分区需要设置hive.exec.dynamic.partition参数值为true,默认值为false,在默认情况下,hive会假设主分区时静态分区,副分区使用动态分区;如果想都使用动态分区,需要设置set hive.exec.dynamic.partition.mode=nostrick,默认为strick
案例:(stat_date=‘20120625’,province)

3.7 Distinct 使用

Hive支持在group by时对同一列进行多次distinct操作,却不支持在同一个语句中对多个列进行distinct操作。

3.8 Hql使用自定义的mapred脚本

注意事项:在使用自定义的mapred脚本时,关键字MAP REDUCE 是语句SELECT TRANSFORM ( … )的语法转换,并不意味着使用MAP关键字时会强制产生一个新的map过程,使用REDUCE关键字时会产生一个red过程。
自定义的mapred脚本可以是hql语句完成更为复杂的功能,但是性能比hql语句差了一些,应该尽量避免使用,如有可能,使用UDTF函数来替换自定义的mapred脚本

3.9 UDTF

UDTF将单一输入行转化为多个输出行,并且在使用UDTF时,select语句中不能包含其他的列,UDTF不支持嵌套,也不支持group by 、sort by等语句。如果想避免上述限制,需要使用lateral view语法,案例:
select a.timestamp, get_json_object(a.appevents, ‘ . e v e n t i d ′ ) , g e t j s o n o b j e c t ( a . a p p e n v e t s , ′ .eventid'), get_json_object(a.appenvets, ' .eventid),getjsonobject(a.appenvets,.eventname’) from log a;
select a.timestamp, b.*
from log a lateral view json_tuple(a.appevent, ‘eventid’, ‘eventname’) b as f1, f2;
其中,get_json_object为UDF函数,json_tuple为UDTF函数。
UDTF函数在某些应用场景下可以大大提高hql语句的性能,如需要多次解析json或者xml数据的应用场景。

3.10 聚合函数count和sum

Count和sum函数可能是在hql语句中使用的最为频繁的两个聚合函数了,但是在hive中count函数在计算distinct value时支持加入条件过滤。

3.11 Hive 中的文件存储格式 & 压缩格式

  • 存储格式
存储格式说明
TextFile默认格式,存储方式为行存储,数据不做压缩,磁盘开销大,数据解析开销大。 可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,压缩后的文件不支持split,Hive不会对数据进行切分,从而无法对数据进行并行操作。并且在反序列化过程中,必须逐个字符判断是不是分隔符和行结束符,因此反序列化开销会比SequenceFile高几十倍。
SequenceFileSequenceFile是Hadoop API提供的一种二进制文件支持,,存储方式为行存储,其具有使用方便、可分割、可压缩的特点。SequenceFile支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。优势是文件和hadoop api中的MapFile是相互兼容的。
RCfile存储方式:数据按行分块,每块按列存储。结合了行存储和列存储的优点:首先,RCFile 保证同一行的数据位于同一节点,因此元组重构的开销很低;其次,像列存储一样,RCFile 能够利用列维度的数据压缩,并且能跳过不必要的列读取;
ORCfile存储方式:数据按行分块 每块按照列存储。压缩快 快速列存取。效率比rcfile高,是rcfile的改良版本。

总结:相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势 。

  • 压缩格式:

检查hadoop支持那些压缩格式

[root@${NN_HOST} ~]# hadoop checknative
/opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/bin/…/lib/hadoop/bin/hadoop
20/03/27 15:29:05 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native
20/03/27 15:29:05 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop: true /opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/lib/hadoop/lib/native/libhadoop.so.1.0.0
zlib: true /lib64/libz.so.1
zstd : true /opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/lib/hadoop/lib/native/libzstd.so.1
snappy: true /opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/lib/hadoop/lib/native/libsnappy.so.1
lz4: true revision:10301
bzip2: true /lib64/libbz2.so.1
openssl: true /lib64/libcrypto.so
ISA-L: true /opt/cloudera/parcels/CDH-6.1.0-1.cdh6.1.0.p0.770702/lib/hadoop/lib/native/libisal.so.2

Hive ORC + SNAPPY
hive常见的几种文件存储格式与压缩方式的结合-------Parquet格式+snappy压缩 以及ORC格式+snappy压缩文件的方式

四. 函数解析

4.1 开窗函数over() /统计函数ntile(num)

详见: Hive窗口函数Over和排序函数Rank

4.2 nvl

nvl(T value, T default_value)

Returns default value if value is null else returns value (as of Hive 0.11).
含义是:如果第一个参数为空那么显示第二个参数的值,如果第一个参数的值不为空,则显示第一个参数本来的值。

coalesce(T v1, T v2, …)

Returns the first v that is not NULL, or NULL if all v’s are NULL.
coalese函数的作用是的NVL的函数有点相似,其优势是有更多的选项
格式如下:
coalesce(expr1, expr2, expr3…… exprn)
表示可以指定多个表达式的占位符。

案例:

select nvl(null, 2), nvl(null,"defaultValue"), nvl(2,'default');
_c0	_c1	_c2
2	defaultValue	2

select coalesce(1,2,3),coalesce(1,null,3),coalesce(null,1,2), coalesce(null,null,2);
_c0	_c1	_c2	_c3
1	1	1	2

其他sql实现如mysql中, 实现相同功能则使用ifnull函数.

select IFNULL(1,0), IFNULL(0,1), IFNULL(1/0,10), IFNULL(1/0,'YES');  --1,0,10,YES
SELECT IF(1<2, 'RIGHT' ,'WRONG'),IF(1>2,2,3);  --RIGHT,3
SELECT CASE 3 WHEN 1 THEN 'ONE' WHEN 2 THEN 'TWO' ELSE 'MORE' END;  --MORE
SELECT CASE WHEN 1>0 THEN "true" ELSE "false" END;   --true
SELECT CASE BINARY "b" when "a" then 1 when "b" then 2 end;   --2

4.3 with as 语法

在开发中有时候要对临时处理一些数据,但是这些数据又不想放到table里面。
或者整个sql的流程繁冗, 且包含着严格的上下级关系, 不想创建太多的中间表(在流程结束位置还要考虑删除).
这个时候可以考虑with as。
with as是在内存中建立一个临时的table, 之后可以对这个temp table里的数据进行处理。另外其也可以和已存在hive里的其他表进行join关联操作.
注意: with as 后必须跟 sql语句(如select), 单独的with as语法会报语法错误.

由于with as是内存中的table, 所以速度还是比较快的。但如果数据量巨大, 建议不要用with as语法, 这样反而会变得很慢。

案例:
内存中构建数据集, 测试left join.

with a as (
select 
1 as id, a as name
union all 
2 as id, b as name
union all 
3 as id, c as name
), b as (
select 
1 as id, 15 as stock
union all 
2 as id, 50 as stock
) 
select a.*,b.* from a left join   b   on   a.id=b.id;

4.4 split

将字符串转化为数组, 如:

split('a,b,c,d' , ',') ==> ["a","b","c","d"] 

遍历数组元素,下标从0开始,如取'b':
split('a,b,c,d' , ',') [1]

4.5 collect_list

将该字段的值组成一个list, 不做去重处理.

4.6 将分区表数据导入另一张同构新表中

Step 1: 创建同构表
create table ${db_name}.${table_name}_temp like ${db_name}.${table_name};

Step 2: 查询源表数据导入新表
insert overwrite table ${db_name}.${table_name}_temp partition(year,month) select * from ${db_name}.${table_name} where ${conditions};
.
egg: 1=1 and ${col_name} is not null;

Step 3: 删除源表
drop table if exists ${db_name}.${table_name};

Step 4: 临时表重命名为新表
alter table ${db_name}.${table_name}_temp rename to ${db_name}.${table_name};

4.7 在hive表指定位置添加列

-- 选择hive某个数据库
use ${DB_NAME};

-- 增加一列
alter table ${TABLE_NAME} add columns (${NEW_ADD_COLUMN} string);

-- 将增加的列放到某一列后面
alter table ${TABLE_NAME} change column ${NEW_ADD_COLUMN} ${NEW_ADD_COLUMN} string after user_name;

-- 将增加的列放到第一列位置
alter table ${TABLE_NAME} change column ${NEW_ADD_COLUMN} ${NEW_ADD_COLUMN} string first;

1.1 beeline方式

参考列表:
-1. 一起学Hive——详解四种导入数据的方式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值