oracle分区表的使用和查询
本文参考了
https://blog.csdn.net/mzglzzc/article/details/46300645
一 创建和使用分区表
1.范围分区(RANGE)
范围分区将数据基于范围映射到每一个分区,这个范围是你在创建分区时指定的分区键决定的。这种分区方式是最为常用的,并且分区键经常采用日期。当使用范围分区时,请考虑以下几个规则:
1)每一个分区都必须有一个VALUES LESS THEN子句,它指定了一个不包括在该分区中的上限值。分区键的任何值等于或者大于这个上限值的记录都会被加入到下一个高一些的分区中。
2)所有分区,除了第一个,都会有一个隐式的下限值,这个值就是此分区的前一个分区的上限值。
3)在最高的分区中,MAXVALUE被定义。MAXVALUE代表了一个不确定的值。这个值高于其它分区中的任何分区键的值,也可以理解为高于任何分区中指定的VALUE LESS THEN的值,同时包括空值。
例一:假设有一个CUSTOMER表,表中有数据200000行,我们将此表通过CUSTOMER_ID进行分区,每个分区存储100000行,我们将每个分区保存到单独的表空间中,这样数据文件就可以跨越多个物理磁盘。下面是创建表和分区的代码,如下:
CREATE TABLE CUSTOMER
(
CUSTOMER_ID NUMBER NOT NULL PRIMARY KEY,
FIRST_NAME<span style="white-space:pre"> </span>VARCHAR2() NOT NULL,
LAST_NAME<span style="white-space:pre"> </span>VARCHAR2() NOT NULL,
PHONE<span style="white-space:pre"> </span>VARCHAR2() NOT NULL,
EMAIL<span style="white-space:pre"> </span>VARCHAR2(),
STATUS<span style="white-space:pre"> </span>CHAR()
)
PARTITION BY RANGE (CUSTOMER_ID)
(
PARTITION CUS_PART1 VALUES LESS THAN () TABLESPACE CUS_TS01,
PARTITION CUS_PART2 VALUES LESS THAN () TABLESPACE CUS_TS02
);
例二:按时间划分
CREATE TABLE ORDER_ACTIVITIES
(
ORDER_ID NUMBER() NOT NULL,
ORDER_DATE DATE,
TOTAL_AMOUNT NUMBER,
CUSTOTMER_ID NUMBER(),
PAID CHAR()
)
PARTITION BY RANGE (ORDER_DATE)
(
PARTITION ORD_ACT_PART01 VALUES LESS THAN (TO_DATE('01- MAY -2003','DD-MON-YYYY')) TABLESPACEORD_TS01,
PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUN-2003','DD-MON-YYYY')) TABLESPACE ORD_TS02,
PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUL-2003','DD-MON-YYYY')) TABLESPACE ORD_TS03
);
例三:MAXVALUE
CREATE TABLE RANGETABLE
(
idd INT PRIMARY KEY ,
iNAME VARCHAR(10),
grade INT
)
PARTITION BY RANGE (grade)
(
PARTITION part1 VALUES LESS THEN (1000) TABLESPACE Part1_tb,
PARTITION part2 VALUES LESS THEN (MAXVALUE) TABLESPACE Part2_tb
); --——在表上执行查询
select * from RANGETABLE; --——在表分区上执行查询
select * from RANGETABLE partition(part1);
2.列表分区(LIST)
该分区的特点是某列的值只有几个,基于这样的特点我们可以采用列表分区。创建一个按字段数据列表固定可枚举值分区的表。插入记录分区字段的值必须在列表中,否则不能被插入。
例一:
CREATE TABLE PROBLEM_TICKETS
(
PROBLEM_ID NUMBER(7) NOT NULL PRIMARY KEY,
DESCRIPTION VARCHAR2(2000),
CUSTOMER_ID NUMBER(7) NOT NULL,
DATE_ENTERED DATE NOT NULL,
STATUS VARCHAR2(20)
)
PARTITION BY LIST (STATUS)
(
PARTITION PROB_ACTIVE VALUES ('ACTIVE') TABLESPACE PROB_TS01,
PARTITION PROB_INACTIVE VALUES ('INACTIVE') TABLESPACE PROB_TS02
);
例二:
CREATE TABLE ListTable
(
id INT PRIMARY KEY ,
name VARCHAR (20),
area VARCHAR (10)
)
PARTITION BY LIST (area)
(
PARTITION part1 VALUES ('guangdong','beijing') TABLESPACE Part1_tb,
PARTITION part2 VALUES ('shanghai','nanjing') TABLESPACE Part2_tb
);
3.哈希分区(散列分区)(HASH)
例一:
CREATE TABLE HASH_TABLE
(
COL NUMBER(8),
INF VARCHAR2(100)
)
PARTITION BY HASH (COL)
(
PARTITION PART01 TABLESPACE HASH_TS01,
PARTITION PART02 TABLESPACE HASH_TS02,
PARTITION PART03 TABLESPACE HASH_TS03
)
简写:
CREATE TABLE emp
(
empno NUMBER (4),
ename VARCHAR2 (30),
sal NUMBER
)
PARTITION BY HASH (empno) PARTITIONS 8
STORE IN (emp1,emp2,emp3,emp4,emp5,emp6,emp7,emp8);
hash分区最主要的机制是根据hash算法来计算具体某条纪录应该插入到哪个分区中,hash算法中最重要的是hash函数,Oracle中如果你要使用hash分区,只需指定分区的数量即可。建议分区的数量采用2的n次方,这样可以使得各个分区间数据分布更加均匀。
4.组合分区(RANGE-LIST 和 RANGE-HASH)
1)基于范围分区和列表分区,表首先按某列进行范围分区,然后再按某列进行列表分区,分区之中的分区被称为子分区。
CREATE TABLE emp
(
empno NUMBER (4),
ename VARCHAR2 (30),
sal NUMBER
)
PARTITION BY HASH (empno) PARTITIONS 8
STORE IN (emp1,emp2,emp3,emp4,emp5,emp6,emp7,emp8);
2)基于范围分区和散列分区,表首先按某列进行范围分区,然后再按某列进行散列分区。
create table dinya_test
(
transaction_id number primary key,
item_id number(8) not null,
item_description varchar2(300),
transaction_date date
)
partition by range(transaction_date)
subpartition by hash(transaction_id) subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03)
(
partition part_01 values less than(to_date(‘2006-01-01','yyyy-mm-dd')),
partition part_02 values less than(to_date(‘2010-01-01','yyyy-mm-dd')),
partition part_03 values less than(maxvalue)
); CREATE TABLE range_hash_example(
range_column_key int,
hash_column_key INT,
DATA <span style="white-space:pre"> </span>VARCHAR2(20)
)
PARTITION BY RANGE(range_column_key)
SUBPARTITION BY HASH(hash_column_key) SUBPARTITIONS 2
(
PARTITION part_1 VALUES LESS THAN (100000000)
(
SUBPARTITION part_1_sub_1,
SUBPARTITION part_1_sub_2,
SUBPARTITION part_1_sub_3
),
PARTITION part_2 VALUES LESS THAN (200000000)
(
SUBPARTITION part_2_sub_1,
SUBPARTITION part_2_sub_2
)
);
--注: subpartitions 2 并不是指定subpartition的个数一定为2,实际上每个分区的子分区个数可以不同。如果不指定subpartition的具体明细,则系统按照subpartitions的值指定subpartition的个数生成子分区,名称由系统定义 。
二 有关分区表的维护操作
1.添加分区
以下代码给SALES表添加了一个P3分区
ALTER TABLE SALES ADD PARTITION P3 VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD'));
注意:以上添加的分区界限应该高于最后一个分区界限。
以下代码给SALES表的P3分区添加了一个P3SUB1子分区
ALTER TABLE SALES MODIFY PARTITION P3 ADD SUBPARTITION P3SUB1 VALUES('COMPLETE');
-- range partitioned table
ALTER TABLE range_example ADD PARTITION part04 VALUES LESS THAN (TO_DATE('2008-10-1 00:00:00','yyyy-mm-ddhh24:mi:ss'));
--list partitioned table
ALTER TABLE list_example ADD PARTITION part04 VALUES('TE');
--Adding Values for a List Partition
ALTER TABLE list_example MODIFY PARTITION part04 ADD VALUES('MIS');
--Dropping Values from a List Partition
ALTER TABLE list_example MODIFY PARTITION part04 DROP VALUES('MIS');
--hash partitioned table
ALTER TABLE hash_example ADD PARTITION part03;
--增加subpartition
ALTER TABLE range_hash_example MODIFY PARTITION part_1 ADD SUBPARTITION part_1_sub_4;
注:hash partitioned table新增partition时,现有表的中所有data都有重新计算hash值,然后重新分配到分区中,所以被重新分配的分区的indexes需要rebuild 。
2.删除分区
ALTER TABLE SALES DROP PARTITION P3;
ALTER TABLE SALES DROP SUBPARTITION P4SUB1;
注意:如果删除的分区是表中唯一的分区,那么此分区将不能被删除,要想删除此分区,必须删除表。
3.截断分区
截断某个分区是指删除某个分区中的数据,并不会删除分区,也不会删除其它分区中的数据。当表中即使只有一个分区时,也可以截断该分区。通过以下代码截断分区:
ALTER TABLE SALES TRUNCATE PARTITION P2;
通过以下代码截断子分区:
ALTER TABLE SALES TRUNCATE SUBPARTITION P2SUB2;
4.合并分区
合并分区是将相邻的分区合并成一个分区,结果分区将采用较高分区的界限,值得注意的是,不能将分区合并到界限较低的分区。
ALTER TABLE SALES MERGE PARTITIONS P1,P2 INTO PARTITION P2 UPDATE INDEXES;
--如果省略update indexes子句的话,必须重建受影响的分区的index;
ALTER TABLE range_example MODIFY PARTITION part02 REBUILD UNUSABLE LOCAL INDEXES;
5.拆分分区
拆分分区将一个分区拆分两个新分区,拆分后原来分区不再存在。注意不能对HASH类型的分区进行拆分。
ALTER TABLE SALES SBLIT PARTITION P2 AT(TO_DATE('2003-02-01','YYYY-MM-DD')) INTO (PARTITION P21,PARTITION P22);
注意:如果是RANGE类型的,使用at,LIST类型的使用values。
6.接合分区(coalesce)
分区接合是针对散列分区或者*-散列子分区的,目的是减少分区数。当某个散列分区接合后,Oracle将其分区的数据分散到其它分区中。被接合的分区是由数据库选择的,接合完成后该分区会被删除,且如果没有使用UPDATE INDEX子句,本地索引和全局索引均将变成不可用,一般需要重建索引。
--散列分区表的散列分区接合
ALTER TABLE table_name COALESCE PARTITION;
--散列分区表的散列子分区接合
ALTER TABLE table_name MODIFY PARTITION partition_name COALESCE SUBPARTITION;
(网上搜索90%的资料都是 接合分区coalesca 然后介绍就一句话和一句SQL……这个词都拼错了好么?!)
7.重命名表分区
ALTER TABLE table_name RENAME PARTITION old_name TO new_name;
ALTER TABLE table_name RENAME SUBPARTITION old_name TO new_name;
8.交换分区
可以将一个分区(子分区)和非分区表进行数据交换,oracle交换的方法是其实是对逻辑存储段进行交换。同样,散列|范围|列表分区可以与复合*-散列|*-范围|*-列表分区间也可以进行数据交换。当应用中需要将非分区表的数据转换进入分区表的分区时非常高效实用。使用INCLUDEING INDEXES子句可以同步将本地索引也进行交换,使用WITH VALIDATATION子句还可以实现行数据的验证。
交换分区时如果不带UPDATE INDEXES子句,则全局索引或全局索引基于的分区将变为不可用。
1)三种单级分区与非分区表的交换
ALTER TABLE table_name EXCHANGE PARTITION partition_name WITH TABLE nonpartition_name;
2)单级散列分区表与复合*-散列分区的交换
此时要求单级散列分区表的分区键与复合*-散列分区表的子分区键相同,且两个交换的散列分区数也得相同,此外也不能指定单级散列分区表的某一个分区进行交换。
3)复合*-散列分区中的散列子分区交换
使用ALTER TABLE ... EXCHANGE SUBPARTITION与非分区表进行交换,且只能跟非分区表进行交换。
4)单级列表分区表与复合*-列表分区的交换
此时要求List分区表的分区键和*-List表的子分区键相匹配,前者的List分区数与后者的List子分区相同。
5)复合*-列表分区中的列表子分区交换
同样也是使用ALTER TABLE ... EXCHANGE SUBPARTITION与非分区表进行交换,且只能跟非分区表进行交换。
6)单级范围分区表与复合*-范围分区表的交换
此时要求Range分区表的分区键和*-Range表的子分区键相匹配,前者的Range分区数与后者的Range子分区相同。
7)复合*-范围分区中的范围子分区交换
同样也是使用ALTER TABLE ... EXCHANGE SUBPARTITION与非分区表进行交换,且只能跟非分区表进行交换。
9.移动分区
alter table custaddr move partition P_OTHER tablespace system;
alter table custaddr move partition P_OTHER tablespace icd_service;
分区移动会自动维护局部分区索引,oracle不会自动维护全局索引,所以需要我们重新rebuild分区索引,具体需要rebuild哪些索引,可以通过dba_part_indexes,dba_ind_partitions去判断。
Select index_name,status From user_indexes Where table_name='CUSTADDR';
10.关于分区表和索引
1)本地分区索引
本地分区索引是使用了LOCAL属性创建的分区索引,其特征是索引分区的所有键均指向其基表某个 唯一分区中存储的相应行。Oracle创建本地分区索引的目的就是要确保索引也是分区管理的,而且索引的分区与表的分区是均衡的,也就是本地分区索引具有与其基表相同的分区、子分区,即分区键等同于表的分区键、分区数等同于表的分区数。
任何基表分区的增加、删除、合并、分割操作,或者散列分区增加或合并操作,Oracle会通过其自身的机制自动维护本地分区索引相应的分区,此即本地分区索引与基表的均衡性原则。
如果分区列能够形成索引列的一个子集,则本地分区索引可以是唯一索引。该限制能确保具有相同索引键的行始终映射到同一个分区,在该分区中,违反唯一性的行为能被检测到。
本地索引的优势有:
l在基表上执行除SPLIT PARTITION或ADD PARTITION 外的维护命令仅仅只有一个分区会被影响
l当分区表只有一个本地分区索引时,对分区进行维护操作的时间是与分区的大小成正比的
l本地分区索引支持分区的独立性
l只能本地分区索引支持单一分区数据的装入和卸出
l本地索引与基表的均衡性会给Oracle执行计划带来更好的性能
l表分区和各自的本地索引可以同时恢复
l分区表中的位图索引必须是本地索引,非分区表上不能建立分区位图索引
①本地前缀索引
本地前缀索引是指以索引列的左前缀来分区的,如果存在子分区则要求其子分区的分区键包含在索引键中。本地前缀索引可以是唯一索引,也可以是非唯一索引。
②本地非前缀索引
本地非前缀索引是指没有以索引列的左前缀来分区的,或者是以索引列的左前缀来分区,但子分区的分区键不在索引键中。本地非前缀索引不可以是唯一索引,除非分区键是索引键的子集(此时是前缀索引)。
2)全局分区索引
全局分区索引是指某个特定索引分区中的键可能指向存储在基表中的多个分区或子分区中的行,其创建需要使用GLOBAL属性。无论分区表是那种类型的分区,全局索引只支持按范围和散列分区两种分区方式。
全局索引往往与基表是不均衡的,如果要追求二者的均衡性,只能使用本地分区索引。全局分区的索引类型只能是b-tree索引,不能是bitmap索引。正是因为其是b-tree索引,所以无论其指向多少个分区抑或多少行,也只有一个b-tree入口,每个索引分区中会再包含指向具体表分区或子分区中的行的键。
全局分区索引必须是前缀的,不支持非前缀的。其中,前缀的意思和本地分区索引的前缀的含义相同,即“前缀索引是指以索引列的左前缀来分区的”。
管理全局分区索引
l当基表分区移动和删除(TRUNCATE、DROP、MOVE、SPLIT)时,全局索引的所有分区都受影响,也不支持分区依赖
l当基表分区或子分区恢复到某个时间点时,全局索引中所有相应入口也要恢复到相同的时间点。由于索引的分区或子分区的入口可能离散分布,其它分区或子分区混合型入口不恢复,除了重建索引之外没有办法完成
以表range_example为例:
1)建立普通的索引
create index com_index_range_example_id on range_example(id); 2)建立本地分区索引
create index local_index_range_example_id on range_example(id) local; 3)建立全局分区索引
create index gidx_range_example_id on range_example(id)
GLOBAL partition by range(id)
(
part_01 values less than(1000),
part_02 values less than(MAXVALUE)
);
对于分区索引的删除,local index 不能指定分区名称,单独的删除分区索引。local index 对应的分区会伴随着data分区的删除而一起被删除。 global partition index 可以指定分区名称,删除某一分区。但是有一点要注意,如果该分区不为空,则会导致更高一级的索引分区被置为UNUSABLE 。 ALTER INDEX gidx_range_exampel_id drop partition part_01 ;
此句将导致part_02 状态为UNUSABLE
注意:对于表分区的各种操作,一定要注意更新索引
三 相关查询
1.跨分区查询
注意查询分区相关信息所有表名用户名需大写,具体看数据库配置
select sum( *) from
(select count(*) cn from t_table_SS PARTITION (P200709_1)
union all
select count(*) cn from t_table_SS PARTITION (P200709_2)
); 2.查询表上有多少分区
SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='tableName'; 3.查询索引信息
select object_name,object_type,tablespace_name,sum(value)
from v$segment_statistics
where statistic_name IN ('physical reads','physical write','logical reads')and object_type='INDEX'
group by object_name,object_type,tablespace_name
order by 4 desc --显示数据库所有分区表的信息:
select * from DBA_PART_TABLES --显示当前用户可访问的所有分区表信息:
select * from ALL_PART_TABLES --显示当前用户所有分区表的信息:
select * from USER_PART_TABLES --显示表分区信息 显示数据库所有分区表的详细分区信息:
select * from DBA_TAB_PARTITIONS --显示当前用户可访问的所有分区表的详细分区信息:
select * from ALL_TAB_PARTITIONS --显示当前用户所有分区表的详细分区信息:
select * from USER_TAB_PARTITIONS --显示子分区信息 显示数据库所有组合分区表的子分区信息:
select * from DBA_TAB_SUBPARTITIONS --显示当前用户可访问的所有组合分区表的子分区信息:
select * from ALL_TAB_SUBPARTITIONS --显示当前用户所有组合分区表的子分区信息:
select * from USER_TAB_SUBPARTITIONS --显示分区列 显示数据库所有分区表的分区列信息:
select * from DBA_PART_KEY_COLUMNS --显示当前用户可访问的所有分区表的分区列信息:
select * from ALL_PART_KEY_COLUMNS --显示当前用户所有分区表的分区列信息:
select * from USER_PART_KEY_COLUMNS --显示子分区列 显示数据库所有分区表的子分区列信息:
select * from DBA_SUBPART_KEY_COLUMNS --显示当前用户可访问的所有分区表的子分区列信息:
select * from ALL_SUBPART_KEY_COLUMNS --显示当前用户所有分区表的子分区列信息:
select * from USER_SUBPART_KEY_COLUMNS --怎样查询出oracle数据库中所有的的分区表
select * from user_tables a where a.partitioned='YES' --删除一个表的数据是
truncate table table_name; --删除分区表一个分区的数据是
alter table table_name truncate partition p5;
oracle分区表的使用和查询的更多相关文章
- oracle 跨分区查询效率,Oracle分区表做跨分区查询
问:有一张大表,其中按时间字段(TIME_ID)进行表分区(按季度分区),但是如果业务人员做跨季度的大批量数据的查询时,未能走TIME_ID分区索引,导致全表扫描.此种情况该如何处理? 示例解析: 1 ...
- Oracle分区表做跨分区查询
问:有一张大表,其中按时间字段(TIME_ID)进行表分区(按季度分区),但是如果业务人员做跨季度的大批量数据的查询时,未能走TIME_ID分区索引,导致全表扫描.此种情况该如何处理? 示例解析: 1 ...
- 谈一下如何设计Oracle 分区表
在谈设计Oracle分区表之间先区分一下分区表和表空间的个概念: 表空间:表空间是一个或多个数据文件的集合,所有数据对象都存放在指定的表空间中,但主要存放表,故称表空间. 分区表:分区致力于解决支持极 ...
- 深入学习Oracle分区表及分区索引
关于分区表和分区索引(About Partitioned Tables and Indexes)对于10gR2而言,基本上可以分成几类: • Range(范围)分区 • Has ...
- oracle 分区表和分区索引
很复杂的样子,自己都没有看完,以备后用 http://hi.baidu.com/jsshm/item/cbfed8491d3863ee1e19bc3e ORACLE分区表.分区索引ORACLE对于分区 ...
- 谈一下怎样设计Oracle 分区表
在谈设计Oracle分区表之间先区分一下分区表和表空间的个概念: 表空间:表空间是一个或多个数据文件的集合,全部数据对象都存放在指定的表空间中,但主要存放表,故称表空间. 分区表:分区致力于解决支持极 ...
- ORACLE分区表、分区索引详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt160 ORACLE分区表.分区索引ORACLE对于分区表方式其实就是将表分段 ...
- 【三思笔记】 全面学习Oracle分区表及分区索引
[三思笔记]全面学习Oracle分区表及分区索引 2008-04-15 关于分区表和分区索引(About PartitionedTables and Indexes) 对于 10gR2 而言,基本上可 ...
- oracle分区表彻底删除的办法,处理删不掉的不规则表名
Oracle分区表彻底删除的办法当对一个不再使用的分区表进行drop后,查询user_tab_partitions视图发现出现如下不规则的分区表表名:SQL> select distinct t ...
随机推荐
- xcode9.4 报错 error:The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
原因 http | https 协议 不能正常使用 找到的解决方案 但是在字段名上有了变化,不过复制进去 还是会自动选择对应的 解决办法 1. 在Info.plist中添加 App Transpor ...
- 记录小白实习生的HashMap源码 put元素 的学习和一些疑问
首先看HashMap存储结构 transient Node<K,V>[] table; static class Node<K,V> implements Map.Entry& ...
- Linux连接虚拟机及操作指令
Linux的安装(虚拟机环境)与基础配置 一.背景 本文介绍如何安装虚拟机VMware以及如果在虚拟机上安装Linux系统以及Linux安装完毕之后的基础配置 需要准备的东西有VMware以及Li ...
- linux系统下常用的命令(吐血自己整理,且用且珍惜)
1)linux命令太多,有时候记不起来是哪个,为了方便大家查询,自己吐血整理了以下这些,转载时请标明出处,珍惜原创成果 吐血自己整理,且用且珍惜) 吐血自己整理,且用且珍惜) 吐血自己整理,且用且珍惜 ...
- LevelDB源码分析-Version
Version VersionSet类 VersionSet管理整个LevelDB的当前状态: class VersionSet { public: // ... // Apply *edit to ...
- ssh命令详解
1.简介: Secure Shell(缩写为SSH),由IETF的网络工作小组(Network Working Group)所制定:SSH为一项创建在应用层和传输层基础上的安全协议,为计算机上的She ...
- 不同应用共享redis应用,但分数据库存储数据
日常开发工作中,常常遇到这种情况 项目A ,需要使用redis 项目B ,也需使用redis …… 原来傻乎乎的在服务器上装几个redis,通过不同的端口号来进行使用 其实redis可用有16个数据库 ...
- python学习Day14 带参装饰器、可迭代对象、迭代器对象、for 迭代器工作原理、枚举对象、生成器
复习 函数的嵌套定义:在函数内部定义另一个函数 闭包:被嵌套的函数 -- 1.外层通过形参给内层函数传参 -- 2.返回内部函数对象----> 延迟执行, 开放封闭原则: 功能可以拓展,但源代 ...
- python note 12 生成器、推导式
1.生成器函数 # 函数中如果有yield 这个函数就是生成器函数. 生成器函数() 获取的是生成器. 这个时候不执行函数# yield: 相当于return 可以返回数据. 但是yield不会彻底中 ...
- 《AlwaysRun!团队》第二次作业:团队项目选题报告
第二次作业:团队项目选题报告 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblog ...