达梦数据库对象管理之分区表

一、背景及相关概念                                      

        在大型的企业应用或企业级的数据库应用中,要处理的数据量通常达到 TB 级,对于这 样的大型表执行全表扫描或者 DML 操作时,效率是非常低的。 为了提高数据库在大数据量读写操作和查询时的效率,达梦数据库提供了对表和索引进 行分区的技术,把表和索引等数据库对象中的数据分割成小的单位,分别存放在一个个单独 的段中,用户对表的访问转化为对较小段的访问,以改善大型应用系统的性能。 DM 提供了水平分区方式。水平分区包括范围、哈希和列表三种方式,企业可以使用合 适的分区方法,如日期(范围)、区域(列表),对大量数据进行分区。由于 DM 划分的分区 是相互独立且可以存储于不同的存储介质上的,完全可满足企业高可用性、均衡 IO、降低 维护成本、提高查询性能的要求。

        分区是指将表、索引等数据库对象划分为较小的可管理片段的技术,每一个片段称为分 区子表或分区索引。一个表被分区后,对表的查询操作可以局限于某个分区进行,而不是整 个表,这样可以大大提高查询速度。 DM 支持对大表进行水平分区。例如,通讯公司将用户通话记录保存在一张表中,一年这个表产生 40GB 的数据。假设要对用户的通话信息按照季度进行统计,那么这样的统计需要在全表范围内进行。如果对表按季度进行水平分区,那么每个分区的大小平均为 10GB左右,这样在进行统计时,只需在 10GB 的范围内进行即可。 DM 采用子表方式创建分区表,分区表作为分区主表,而每一个分区以一个子表实体存 在,即每一个分区都是一个完整的表,一般命名为主表名_分区名。对于水平分区,子表跟 主表具有相同的逻辑结构,即分区子表与分区主表有相同的列定义和约束定义。在 DM 分区 表中,主表本身不存储数据,所有数据只存储在子表中,从而实现不同分区的完全独立性。 水平分区子表删除后,会将子表上的数据一起删除。

二、达梦数据库对象的逻辑结构

1、达梦数据库的对象管理逻辑结构是什么?

        DM数据库的逻辑单元从大到小依次为:数据库–>表空间–>数据文件–>段–>簇(区)–>页。到页就没有了,由此看出页是最小的逻辑单元,是数据库最小的分配单位。数据库由一个或多个表空间组成。每一个表空间有一个或多个数据文件组成,每一个数据文件由一个或多个簇组成,段是簇的上级逻辑单位,一段可以跨多个数据文件,簇是磁盘上连续的页组成的。一个簇总在一个数据文件中。大体结构如下所示:

 页(块):数据块,最小的数据IO单元。页的大小可以设置为4K,8k,16k,32k,默认8k。
数据页包含4个部分:页头控制信息,数据,空闲空间,行偏移数组。

簇(区):簇是数据页的上级逻辑单元,由同一个数据文件中 16 个或 32 个或 64 个连续的数据页组成。在 DM 数据库中,簇的大小由用户在创建数据库时指定,默认大小为 16。假定某个数据文件大小为 32MB,页大小为 8KB,则共有 32MB/8KB/16=256 个簇(256个区),每个簇的大小为 8K*16=128K。和数据页的大小一样,一旦创建好数据库,此后该数据库的簇的大小就不能够改变。

段:段是簇的上级逻辑分区单元,它由一组簇组成。在同一个表空间中,段可以包含来自不同文件的簇,即一个段可以跨越不同的文件。而一个簇以及该簇所包含的数据页则只能来自 一个文件,是连续的 16 或者 32 个数据页。由于簇的数量是按需分配的,数据段中的不同簇在磁盘上不一定连续。

        达梦数据库是以簇为最小的物理单元,为数据库分配物理存储空间,簇大小可以设置为16或者32,默认为16,每个簇的大小=页大小x页数(簇大小参数设置的值),所以页大小设置越大,数据文件的物理大小就会越大,在系统运行时,每次从磁盘调入内存的数据单位也就越大,磁盘的IO量也就越大,所以在规划数据库前期,需要慎重考虑数据库页大小及簇大小的选择。

下面是一个对应的参考表,因部署环境、数据库版本、字符选择等因素,表中数据会存在一定的差异:

数据库页大小

每个字符类型字段实际最大长度(字节)

每行记录除大字段外其他字段总长度(字节)

表空间单个数据文件的最小(MB)/最大大小(MB)

4k

1900

2000

16/ 8388608

8k

3900

4000

32/ 16777216

16k

8000

8000

64/ 33554432

32k

8188

16000

128/ 67108864

        为了更好第捷荣其他数据库迁移过来的表数据列存储,达梦推荐页大小32KB,支持更大表空间物理文件的后续扩展。

2、分区条件(什么条件下适合分区表)。

        当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会下降,这时就应该考虑对表进行分区。表进行分区后,逻辑上表仍然是一张完整的表,只是将表中的数据在物理上存放到多个“表空间”(物理文件上),这样查询数据时,不至于每次都扫描整张表而只是从当前的分区查到所要的数据大大提高了数据查询的速度。

oracle
When to Partition a Table什么时候需要分区表,官网的2个建议如下:

Tables greater than 2GB should always be considered for partitioning.
Tables containing historical data, in which new data is added into the newest partition. A typical example is a historical table where only the current month's data is updatable and the other 11 months are read only.
中文大概就是:
1、表的大小超过2GB。
2、表中包含历史数据,新的数据被增加都新的分区中。

通俗地说就是,满足以下条件即考虑分区表:

 3、达梦数据库分区表的功能介绍

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、一张表最多能存多少条数据?

 1、ORACLE

按Oracle设计:1个表空间(tablespace),最多由1022个文件数据文件组成(datafile),每个文件最大32GB,那么

1)一个表空间占用约:32TB空间。
        如程序员设计:1条记录占用0.1KB空间,那么
2)一个表空间包括约:320G条记录(=32TB/.1KB),就是3千亿条记录。

 2、MySQL

        对于myslq innodb存储引擎而言,默认页大小16KB,存储数据量跟B+tree索引组织结构有关系,按照一个3级索引树来说,单表支持千万级数据量的存储,一般超过2千万即考虑分区分表策略。

3、DM8 

  • 单个表空间最多可以添加256个数据文件。这个可以从TS_MAX_ID和TS_FIL_MAX_ID这两个参数的值来确定。TS_FIL_MAX_ID:限制每个表空间所支持的最大文件个数,范围(2 ~255);TS_MAX_ID:限制系统所支持的最大表空间ID,有效值范围(5 ~ 65517),与系统实际最大ID比较,取最大值。

  • DM 数据文件大小,最小值不能低于页大小的 4096 倍(如果页大小是 8K,最小值将不低于 32M),最大值为页大小的 2 的 31 次方-1(如果页大小是 8K,最大值为 16T-1)。对于32KB页大小,支持64TB最大数据文件大小。

  • 一张表最大即256个表空间*64TB/32KB=50亿个数据页,如果一个32KB数据页能存10条数据,单张表最大存储500亿条数据。

5、分区表和分表分库的区别

分区表:

        分区的意思是指将同一表中不同行的记录分配到不同的分区中,每个区都是独立的,可以独立处理,也可以作为一个更大对象的一部分进行处理。

分表分库:

分库分表标准

  • 存储占用100G+
  • 数据增量每天200w+
  • 单表条数1亿条+

分库分表字段
分库分表字段取值非常重要

  • 在大多数场景该字段是查询字段
  • 数值型

总结:

        分区表和分表分库在用途上不一样,分表分库是为了承接超大规模的表,单机放不下那种。分区表的话则一般都是放在单机里的,用的比较多的是时间范围分区,方便归档。

三、达梦支持分区表的类型

        达梦数据库目前只支持水平分区表:表按照行拆分成多个分区,每个分区和主表有相同的列和约束条件。

目前水平分区主要支持4种类型,达梦数据库 DM 支持对表进行水平分区。对于水平分区,提供以下分区方式:
1. 范围(range)水平分区:对表中的某些列上值的范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上;管理分区表和分区索引
2. 哈希(hash)水平分区:通过指定分区编号来均匀分布数据的一种分区类型,通过在 I/O 设备上进行散列分区,使得这些分区大小基本一致;
3. 列表(list)水平分区:通过指定表中的某个列的离散值集,来确定应当存储在一起的数据。例如,可以对表上的 status列的值在('A','H','O')放在一个分区,值在('B','I','P')放在另一个分区,以此类推;
4. 多级分区表:按上述三种分区方法进行任意组合,将表进行多次分区,称为多级分区表。

1、范围分区     

说明:针对记录字段的值在某个范围。
规则:
(1)、每一个分区都必须有一个VALUES LESS THEN子句,它指定了一个不包括在该分区中的上限值。
分区键的任何值等于或者大于这个上限值的记录都会被加入到下一个高一些的分区中。
(2)、所有分区,除了第一个,都会有一个隐式的下限值,这个值就是此分区的前一个分区的上限值。
(3)、在最高的分区中,MAXVALUE被定义。MAXVALUE代表了一个不确定的值。这个值高于其它分区中的任何分区键的值,
也可以理解为高于任何分区中指定的VALUE LESS THEN的值,同时包括空值。若不添加maxvalue的分区插入数值一旦超过设置的最大上限会报错。

分区表分区处于同一表空间

"""使用时间列来做分区列"""

create table part_range_t1(
id number,
name varchar2(20),
birthday date)
partition by range(birthday)(
        partition p1 values less than(to_date('2001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')),
        partition p2 values less than(to_date('2002-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')),
        partition p3 values less than(to_date('2003-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS'))
)
/

TNS_PDB01>select table_owner,table_name,partition_name,tablespace_name from dba_tab_partitions where table_name = 'PART_RANGE_T1';

TABLE_OWNE TABLE_NAME	   PARTITION_ TABLESPACE
---------- --------------- ---------- ----------
SCOTT	   PART_RANGE_T1   P1	      USERS
SCOTT	   PART_RANGE_T1   P2	      USERS
SCOTT	   PART_RANGE_T1   P3	      USERS

@TNS_PDB01>select * from dba_part_key_columns where name = 'PART_RANGE_T1';

OWNER	   NAME 	   OBJEC COLUMN_NAM COLUMN_POSITION COLLATED_COLUMN_ID
---------- --------------- ----- ---------- --------------- ------------------
SCOTT	   PART_RANGE_T1   TABLE BIRTHDAY		  1

@TNS_PDB01>select table_name,partitioning_type from dba_part_tables where table_name = 'PART_RANGE_T1';

TABLE_NAME		       PARTITION
------------------------------ ---------
PART_RANGE_T1		       RANGE

"""使用数字列做为分区列"""

create table p_t3(
n number,
name varchar2(20))
partition by range(n)(
partition p1 values less than(1000),
partition p2 values less than(10000),
partition p3 values less than(maxvalue))

分区表分区处于不同表空间

create table part_range_t3(
id number,
name varchar2(20),
birthday date)
partition by range(birthday)(
partition p1 values less than(to_date('2001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')) tablespace tbs1,
partition p2 values less than(to_date('2010-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')) tablespace tbs2,
partition p3 values less than(maxvalue) tablespace users)
/

@TNS_PDB01>select table_name,partition_name,tablespace_name from dba_tab_partitions where table_name = 'PART_RANGE_T3';

TABLE_NAME		       PARTITION_ TABLESPACE
------------------------------ ---------- ----------
PART_RANGE_T3		       P1	  TBS1
PART_RANGE_T3		       P2	  TBS2
PART_RANGE_T3		       P3	  USERS

@TNS_PDB01>select * from dba_part_key_columns where name = 'PART_RANGE_T3';

OWNER	   NAME 	   OBJEC COLUMN_NAM COLUMN_POSITION COLLATED_COLUMN_ID
---------- --------------- ----- ---------- --------------- ------------------
SCOTT	   PART_RANGE_T3   TABLE BIRTHDAY		  1

@TNS_PDB01>select table_name,partitioning_type from dba_part_tables where table_name = 'PART_RANGE_T3';

TABLE_NAME		       PARTITION
------------------------------ ---------
PART_RANGE_T3		       RANGE

2、列表分区

范围分区是按照某个列上的数据范围进行分区的,如果某个列上的数据无法通过划分范
围的方法进行分区,并且该列上的数据是相对固定的一些值,可以考虑使用 LIST 分区。一
般来说,对于数字型或者日期型的数据,适合采用范围分区的方法;而对于字符型数据,取
值比较固定的,则适合于采用 LIST 分区的方法。

list分区:
说明:该分区的特点是某列的值只有有限个值,基于这样的特点我们可以采用列表分区。
规则:默认分区为DEFAULT,若不添加DEFAULT的分区插入数值不属于所设置的分区会报错。
列表分区:适合适合字符串类型的。一般用于区号,城市,国别,分散较小的数值。
列表分区不支持拆分分区,后期不能进行拆分。
列表分区如果不创建default分区,不会把其他数据写入到数据表中。后期只能添加default 分区。


create table part_list_t1(
id number,
name varchar2(20),
sex char(1))
partition by list(sex)(
partition male values('M') tablespace tbs1,
partition female values('F') tablespace tbs2)

@TNS_PDB01>select table_owner,table_name,partition_name,tablespace_name from dba_tab_partitions where table_name = 'PART_LIST_T1';

TABLE_OWNE TABLE_NAME			  PARTITION_ TABLESPACE
---------- ------------------------------ ---------- ----------
SCOTT	   PART_LIST_T1 		  FEMALE     TBS2
SCOTT	   PART_LIST_T1 		  MALE	     TBS1

@TNS_PDB01>select table_name,partitioning_type from dba_part_tables where table_name = 'PART_LIST_T1';

TABLE_NAME		       PARTITION
------------------------------ ---------
PART_LIST_T1		       LIST

@TNS_PDB01>select * from dba_part_key_columns where name = 'PART_LIST_T1';

OWNER	   NAME 	   OBJEC COLUMN_NAM COLUMN_POSITION COLLATED_COLUMN_ID
---------- --------------- ----- ---------- --------------- ------------------
SCOTT	   PART_LIST_T1    TABLE SEX			  1

create table part_list_t2(
id number,
name varchar2(20),
age number)
partition by list(age)(
partition p1 values(10) tablespace tbs1,
partition p2 values(20) tablespace tbs2,
partition p3 values(default) tablespace users)
/

default --存储age列上除了10、20外的其他值

指定多个值
create table part_list_t2(
id number,
name varchar2(20),
age int)
partition by list(age)(
partition age_10_20 values(10,20),
partition age_30 values(30),
partition age_40_50 values(40,50),
partition age_default values(default))
/

@TNS_PDB01>select table_name,partition_name,tablespace_name,high_value from dba_tab_partitions where table_name = 'PART_LIST_T2';

TABLE_NAME		       PARTITION_NAME		      TABLESPACE HIGH_VALUE
------------------------------ ------------------------------ ---------- ------------------------------
PART_LIST_T2		       AGE_10_20		      USERS	 10, 20
PART_LIST_T2		       AGE_30			      USERS	 30
PART_LIST_T2		       AGE_40_50		      USERS	 40, 50
PART_LIST_T2		       AGE_DEFAULT		      USERS	 default

3、哈希分区

哈希分区的特点:存数据非常快,取数据很慢,所有数据是平均分配到各个子分区。

在很多情况下,用户无法预测某个列上的数据变化范围,因而无法实现创建固定数量的
范围分区或 LIST 分区。
在这种情况下,DM 哈希分区提供了一种在指定数量的分区中均等地划分数据的方法,
基于分区键的散列值将行映射到分区中。当用户向表中写入数据时,数据库服务器将根据一
个哈希函数对数据进行计算,把数据均匀地分布在各个分区中。在哈希分区中,用户无法预
测数据将被写入哪个分区中。

说明:这类分区是在列值上使用散列算法,以确定将行放入哪个分区中。
规则:当列的值没有合适的条件,没有范围的规律,也没有固定的值,建议使用散列分区。
散列分区为通过指定分区编号来均匀分布数据的一种分区类型,因为通过在I/O设备上进行散列分区,
使得这些分区大小一致。建议分区的数量采用2的n次方,这样可以使得各个分区间数据分布更加均匀。

Example:
创建hash分区有两种方法:一种方法是指定分区的名字,另一种方法是指定分区数量。

例一、常规方法指定分区名字

create table part_hash_t1(id number,name varchar2(20),age int)
partition by hash(age)(
partition p1 tablespace tbs1,
partition p2 tablespace tbs2)
/

例二、指定分区数量

create table part_hash_t2(id number,name varchar2(20),age int)
partition by hash(age) partitions 2 store in(tbs1,tbs2)
/

@TNS_PDB01>select table_name,partition_name,tablespace_name from dba_tab_partitions where table_name = 'PART_HASH_T2';

TABLE_NAME		       PARTITION_ TABLESPACE
------------------------------ ---------- ----------
PART_HASH_T2		       SYS_P388   TBS1
PART_HASH_T2		       SYS_P389   TBS2

@TNS_PDB01>select table_name,partitioning_type from dba_part_tables where table_name = 'PART_HASH_T2';

TABLE_NAME		       PARTITION
------------------------------ ---------
PART_HASH_T2		       HASH

@TNS_PDB01>select * from dba_part_key_columns where name = 'PART_HASH_T2';

OWNER	   NAME 	   OBJEC COLUMN_NAM COLUMN_POSITION COLLATED_COLUMN_ID
---------- --------------- ----- ---------- --------------- ------------------
SCOTT	   PART_HASH_T2    TABLE AGE			  1

--往往我们不需要知道hash分区的名字,因为数据放在哪个分区是dm根据hash算法存放的,并不是用户指定,
所以当用户插入一条记录,并不能确定放在哪个分区,这个不同于range和list

查询数据是否平均分配 注意:这里需要注意的是需要在模式面加.来直接跟表的分区的名称进行查看。

4、非分区表变成分区表

1、把非分区表变成分区表需要把数据导出后,删除原表或者从新建分区表,把原有数据导出后在导入新的表中

*/

DROP TABLE TEST.T_R9; --删除表

CREATE TABLE TEST.T_R9(ID INT,NAME VARCHAR(20));----创建一张普通表。

begin
for i in 1..100000 LOOP
 insert into test.T_R9 VALUES(i,'AAA'||i);
 END LOOP;
COMMIT;
END;         ------------写入数据到这张T_R9表。


--导出T_R9这张表。通过dexp 或者dimp 进行导出导入

./dexp SYSDBA/SYSDBA@192.168.1.11:5236 FILE=/dm7/dexp.dmp tables=test.t_r9

./dimp SYSDBA/SYSDBA@192.168.1.11:5236 FILE=/dm7/T_R9.dmp TABLES=TEST.T_R9 IGNORE=Y


CREATE TABLE TEST.T_R9 (
ID INT,
NAME VARCHAR(20))
PARTITION BY RANGE(ID)
(PARTITION P1 VALUES LESS THAN (10000),
PARTITION P2 VALUES LESS THAN (20000),
PARTITION P3 VALUES LESS THAN (30000),
PARTITION PN VALUES LESS THAN (MAXVALUE));

四、分区表的优略势

        由于每一个分区都以一个子表作为实体,那么不同分区可以存储于相同表空间,也可以位于不同的表空间中。将这些分区放在不同的表空间中具有以下的好处:

    优势:

​
1、分散性:由于将数据分散到各个分区中,减少了数据损坏的可能性。

2、改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。

3、增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;

4、维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;

5、均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能。

​

缺点:
         已经存在的表没有方法可以直接转化为分区表。

DM 水平分区表有如下限制条件:

分区列类型必须是数值型、字符型或日期型,不支持 BLOB、CLOB、IMAGE、TEXT、LONGVARCHAR、BIT、BINARY、VARBINARY、LONGVARBINARY、时间间隔类型和用户自定义类型为分区列;
范围分区和哈希分区的分区键可以多个,最多不超过 16 列;LIST 分区的分区键必须唯一;
水平分区表指定主键和唯一约束时,分区键必须都包含在主键和唯一约束中;
水平分区表不支持临时表;
不能在水平分区表上建立自引用约束;
普通环境中,水平分区表的各级分区数的总和上限是 65535;MPP 环境下,水平分区表的各级分区总数上限取决于 INI 参数 MAX_EP_SITES,上限为 2 ^( 16 -log2MAX_EP_SITES)。比如:当 MAX_EP_SITES 为默认值 64 时,分区总数上限为 1024;
不允许对分区子表执行任何 DDL 操作;
哈希分区支持重命名、增加/删除约束、设置触发器是否启用的修改操作;
范围分区支持分区合并、拆分、增加、删除、交换、重命名、增加/删除约束、设置触发器是否生效操作;
 LIST 分区支持分区合并、拆分、增加、删除、交换、重命名、增加/删除约束、设置触发器是否生效操作;
 LIST 分区范围值不能为 NULL;
 LIST分区子表范围值个数与数据页大小和相关系统表列长度相关,存在以下限制:
	1) 4K 页,单个子表最多支持 120 个范围值;
	2) 8K 页,单个子表最多支持 254 个范围值;
	3) 16K\32K 页,单个子表最多支持 270 个范围值;
 对范围分区增加分区值必须是递增的,即只能在最后一个分区后添加分区。LIST分区增加分区值不能存在于其他已存在分区;
 当分区数仅剩一个时,不允许删除分区;
 仅能对相邻的范围分区进行合并,合并后的分区名可为高分区名或新分区名;
 拆分分区的分区值必须在原分区范围中,并且分区名不能跟已有分区名相同;
 与分区进行分区交换的普通表,必须与分区表拥有相同的列及索引,但交换分区并不会对数据进行校验,即交换后的数据并不能保证数据完整性,如 CHECK 约束;分区表与普通表创建的索引顺序要求一致;
 不能对水平分区表建立全局聚集索引、局部唯一函数索引或全文索引;
 不能对分区子表单独建立索引;
 在未指定 ENABLE ROW MOVEMENT 的分区表上执行更新分区键,不允许更新后数据发生跨分区的移动,即不能有行迁移;
 不能在分区语句的 STORAGE 子句中指定 BRANCH 选项;
 不允许引用水平分区子表作为外键约束;
 多级分区表最多支持八层;
 多级分区表支持下列修改表操作:新增分区、新增列、删除列、删除表级约束、修改表名、设置与删除列的默认值、设置列 NULL 属性、设置列可见性、设置行迁移属性、启用超长记录、with delta、新增子分区、删除子分区、修改二级分区模板信息;
 水平分区表支持的列修改操作除了多级分区表支持的操作外,还支持:设置触发器生效/失效、修改列名、修改列属性、增加表级主键约束、删除分区、SPLIT/MERGE分区和交换分区;
 水平分区表中包含大字段、自定义字段列,则定义时指定 ENABLE ROW MOVEMENT 参数无效,即不允许更新后数据发生跨分区的移动;
 间隔分区表的限制说明:
	1) 仅支持一级范围分区创建间隔分区;
	2) 只能有一个分区列,且分区列类型为日期或数值;
	3) 对间隔分区进行 SPLIT,只能在间隔范围内进行操作;
	4) 被 SPLIT/MERGE 的分区,其左侧分区不再进行自动创建;
	5) 不相邻的间隔的分区,不能 MERGE;
	6) 表定义不能包含 MAXVALUE 分区;
	7) 不允许新增分区;
	8) 不能删除起始间隔分区;
	9) 间隔分区表定义语句显示到起始间隔分区为止;
	10)自动生成的间隔分区,均不包含边界值;
	11)间隔表达式只能为常量 或 日期间隔函数。日 期间隔函数为:NUMTOYMINTERVAL、NUMTODSINTERVAL;数值常量可以为整型、DEC 类 型;
	12)MPP 下不支持间隔分区表。
DM 武汉达梦数据库股份有限公司
24小时免费服务热线:400 991 6599
达梦在线服务平台:https://eco.dameng.com

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值