概述
百胜中国作为一家在全球范围内具有广泛影响力的连锁餐饮企业,在其运营的各个环节中对Oracle数据库进行了大量且深入的应用。
为保障Oracle稳定、高效地运行以及运维工作流程的顺畅,同时为给开发人员提供清晰且准确的指导,使其在开发过程中能够正确、合理地使用Oracle,IT运维团队充分考虑了Oracle自身的技术特点以及公司当前的实际运营情况和需求,制定了此份技术白皮书。
该技术白皮书可供DBA、系统应用运维人员以及应用开发者使用。随着百胜中国的Oracle管理策略不断发展,其内容也将持续扩展和更新。
一、Oracle介绍
-
Oracle简介
Oracle是一款商业关系型数据库管理系统,通过将数据存储在不同的表中,有效地提高了访问速度和灵活性。
凭借很好的并行处理能力、系统可移植性好、使用方便、功能强大等特性,被广泛应用于各个领域,是一种高效率,可靠性好、适应高吞吐量的数据库解决方案。
其发展历程丰富,从最初基于汇编语言开发的版本,逐步演进到如今功能强大、全面支持云计算和大数据的现代数据库管理系统。
-
Oracle 体系架构
Oracle数据库采用多进程、多线程的体系结构,主要由实例(Instance) 和数据库(Database) 两大部分组成:
- 实例:是内存结构和后台进程的集合,负责管理数据库的运行和访问。
- 数据库:是数据文件、控制文件、重做日志文件等物理文件的集合,用于持久化存储数据。这种分离的架构设计使得Oracle能够高效地管理内存和磁盘资源,确保系统的稳定性和可扩展性。
1.内存结构
Oracle实例的内存结构主要包括系统全局区(SGA)和程序全局区(PGA)
-
SGA:是共享内存区域,由所有服务器进程和后台进程共享,包含以下重要组件:
- 数据库缓冲池:用于缓存从数据文件中读取的数据块,提高数据访问速度。
- 共享池:存储 SQL 语句和 PL/SQL 程序单元的解析结果,减少重复解析的开销。
- 重做日志缓冲区:记录对数据库的修改操作,用于故障恢复。
-
PGA:是每个服务器进程私有的内存区域,用于存储该进程运行时的私有数据和控制信息。
2.后台进程
Oracle 后台进程负责执行各种系统任务,保障数据库的正常运行。常见的后台进程如下:
- DBWR(数据库写进程):负责将修改后的数据块从数据库缓冲池写入数据文件。
- LGWR(日志写进程):将重做日志缓冲区中的内容写入重做日志文件。
- CKPT(检查点进程):负责协调数据库的检查点操作,确保数据的一致性。
- SMON(系统监控进程):在数据库启动时执行恢复操作,并清理不再使用的临时段。
- PMON(进程监控进程):负责监控服务器进程的状态,在进程出现故障时进行恢复。
3. Database数据库
Database由一堆物理文件组成,主要用于存储数据。其中主要包含三种类型的文件:Data Files、Control Files、Redo Log Files,此外还有 Parameter File、Password File、Archived Log Files 等。
-
Data Files(数据文件)
- Data Files 用于存储数据,Table 中的数据都保存在 Data Files 中。
- 1 个 Data File 对应磁盘上的 1 个物理操作系统文件。
- Data Files 中频繁访问的数据块会缓存在 Database Buffer Cache 中。
- 新的数据块不会立刻写出到 Data Files,而是在 DBWR 处于活动状态时再写出。
-
Control Files(控制文件)
- Oracle 为操作 Data File 提供了 Control Files,这些文件主要记录数据库的控制信息。
- 用于维护数据库对象的状态,以及数据库的元数据(如数据库名称、数据库创建时间、所有数据文件和重做日志文件的名称及位置等数据库自身物理结构的数据)
-
Redo Log Files(重做日志文件)
-
Redo Log Files 记录数据库的改变,只要对数据库进行了修改(如 insert、delete、update),就要将修改前和修改后的状态都记录其中,其作用是恢复 Data File。
- 例如:数据库有一个事务需要提交,但提交失败,事务要回滚,其依据就来自 Redo Log Files。因为 Redo Log Files 记录着数据库的改变,若需要回滚,就从 Redo Log Files 中取出数据,将 Data Files 恢复到修改前的状态。
-
有 3 种状态:Active、Inactive、Current。
-
-
Parameter File(参数文件)
- 任何一个数据库都必须有参数文件,该文件规定了 Oracle 中的一些基本参数和初始化参数的值。
-
Archived Log Files(归档日志文件)
- Archived Log Files 和 Redo Log Files 相辅相成。Redo Log Files 是一个反复利用的过程,通常有几个(一般为 3 个)固定的文件依次使用,用满后,Oracle 会再次从文件头开始写入,覆盖以前的内容。
- 为进一步加强数据库的备份恢复能力,在覆盖之前会把这些修改信息归档到 Archived Log Files 中。
-
Password File(密码文件)
- 用于在用户客户端连接到后台数据库系统时存储口令。
-
Oracle 适用场景
Oracle数据库凭借其高性能、高可靠性、可扩展性以及强大的数据管理功能,在百胜餐饮的多个业务领域有着广泛且重要的适用场景:
1.企业资源规划(ERP)系统
百胜餐饮作为全球性连锁企业,其ERP系统涵盖财务、人力资源、供应链、生产等众多核心业务流程。数据量庞大且复杂,对数据的完整性、一致性和可靠性要求极高。Oracle数据库凭借强大的事务处理能力、高并发支持和数据管理功能,确保了ERP系统中大量业务数据的准确存储和高效访问。以满足企业日常运营和决策分析的需求,保障各业务环节的顺畅运转。
2.客户关系管理(CRM)系统 百胜餐饮需要存储和管理海量的客户信息、销售数据以及市场活动记录等,以便更好地了解客户需求、提升客户满意度和优化营销策略。Oracle数据库具备良好的扩展性和性能表现,能够快速响应用户的查询和操作请求。同时,它提供强大的数据安全保障机制,保护企业的核心客户数据不被泄露和篡改。百胜餐饮借助Oracle数据库,为客户提供优质的服务体验,实现客户关系的有效管理。
3. 数据仓库与商业智能(BI) :在数据仓库和商业智能领域,百胜餐饮需要对海量的历史数据进行存储、整合和分析,以支持企业的战略决策制定。Oracle数据库的高级分析功能、数据压缩技术和并行处理能力,使其能够高效地处理大规模的数据集合,快速生成复杂的报表和分析结果。
4.餐饮门店运营管理系统:百胜餐饮分布在全球各地的众多门店,日常运营中会产生大量的数据,如订单数据、库存数据、销售数据等。Oracle数据库能够高效存储和管理这些数据,支持门店运营系统的稳定运行,确保数据的实时性和准确性,帮助门店管理人员及时掌握运营情况,做出合理决策。
5.供应链管理系统:百胜餐饮的供应链涉及原材料采购、库存管理、物流配送等多个环节,数据交互频繁且数据量巨大。Oracle数据库可以保障供应链管理系统中数据的完整性和一致性,提高供应链的透明度和协同效率。例如,通过实时跟踪原材料的采购进度、库存水平和配送情况,确保原材料的及时供应,降低库存成本,提高运营效率。
二、技术规范
-
版本规范
目前百胜运维团队支持对如下Oracle版本的交付与维护工作:
- Oracle 12.1+
- Oracle 12.2+
- 目前默认交付12.2.0.1版本
-
架构使用
百胜运维团队对Oracle支持交付与运维的高可用架构有: 单实例、RAC 和 Data Guard 3种。交付的Oracle运维清单列表见附录。
几种架构的对比如下:
a. 单实例数据库
-
架构概述:单实例数据库是最基本的数据库架构,一个数据库实例运行在一台服务器上,所有的数据库组件,包括数据库引擎、内存结构、后台进程等都在同一个服务器上运行,并且只能访问本地的存储设备。
-
优点
- 简单性:架构简单,易于安装、配置和管理,不需要复杂的集群或容灾技术,适合小型企业或对数据库管理要求不高的场景。
- 成本效益:硬件和软件成本相对较低,只需要一台服务器和相应的数据库软件许可证即可,适用于预算有限的情况。
-
缺点
- 可用性限制:一旦服务器出现故障,整个数据库将无法使用,导致业务中断,因此可用性相对较低。
- 性能瓶颈:由于所有的处理都在一台服务器上进行,当业务量增长到一定程度时,可能会遇到性能瓶颈,难以满足高并发和大规模数据处理的需求。
-
适用场景:适用于小型企业、个人用户或一些非关键业务系统,这些系统对数据库的性能和可用性要求不高,并且预算有限,无法承担复杂的数据库架构和高昂的成本。
b. Data Guard
-
架构概述:Data Guard 是一种数据库容灾和数据保护架构,通过在不同的地理位置建立主数据库和一个或多个备用数据库,实现数据的实时同步和故障转移。主数据库负责处理所有的业务交易,备用数据库则通过接收主数据库的重做日志并应用来保持与主数据库的数据一致性。
-
优点
- 数据保护:提供了强大的数据保护机制,能够防止数据丢失,即使主数据库发生灾难,也可以快速切换到备用数据库,保证业务的连续性。
- 灾难恢复:在主数据库出现故障时,可以自动或手动将备用数据库切换为主数据库,实现快速的灾难恢复,减少停机时间。
- 性能优化:可以将一些只读查询或报表任务分配到备用数据库上执行,减轻主数据库的负载,提高整体系统性能。
-
缺点
- 网络要求:需要稳定、高速的网络连接来保证主备数据库之间的数据同步,网络延迟或故障可能会影响数据的一致性和切换的及时性。
- 管理复杂性:配置和管理 Data Guard 环境需要一定的技术知识和经验,特别是在进行故障切换和维护时,需要谨慎操作,以避免数据丢失或不一致的情况发生。
-
适用场景:适用于对数据安全性和业务连续性要求极高的企业,如银行、证券、保险等金融机构,以及一些关键业务系统,如政府部门的核心业务系统、大型企业的 ERP 系统等。
c. RAC(Real Application Clusters)
-
架构概述:RAC 是一种分布式数据库架构,允许多个数据库实例同时访问共享的数据库存储。这些实例可以运行在不同的服务器上,通过高速网络连接形成一个集群。每个实例都有自己的内存结构和后台进程,但共享同一个数据库的数据文件、控制文件和重做日志文件等。
-
优点
- 高可用性:当一个实例出现故障时,其他实例可以继续提供服务,不会导致数据库停机,从而实现了数据库的高可用性。
- 可扩展性:可以根据业务需求动态添加或减少实例,以满足不断变化的工作负载要求,实现性能的线性扩展。
- 负载均衡:能够自动将用户的数据库请求分配到不同的实例上,实现负载均衡,提高系统的整体性能和响应速度。
-
缺点
- 复杂性:RAC 的架构和管理相对复杂,需要专业的技术人员进行安装、配置和维护。
- 成本:硬件成本较高,需要多台服务器和共享存储设备,软件许可证费用也相对较高。
-
适用场景:适用于对高可用性和可扩展性要求较高的大型企业级应用,如电信、金融、电子商务等领域,这些应用通常需要处理大量的并发用户和数据,并且不能容忍长时间的停机。
三、部署规范
-
硬件环境要求
为了确保 Oracle 数据库在百胜生产环境中能够稳定、高效地运行,对服务器硬件环境有一定的要求。服务器处理器应具备足够的核心数和主频,以满足多任务处理和复杂查询的需求。内存容量需根据数据库的大小和并发访问量进行合理配置,一般建议每 100GB 的数据库至少配置 16GB 的内存。存储设备方面,应采用高速、可靠的磁盘阵列,如 RAID 10 或 RAID 5,以提供数据冗余和高性能的 I/O 读写能力。网络方面,服务器应配备千兆或万兆网卡,确保网络带宽能够满足数据传输的需求。
-
操作系统选择
百胜中国推荐在 Oracle 数据库部署中使用 Linux 操作系统,具体版本为 Red Hat Enterprise Linux 7 或 CentOS Linux release 7。Linux 操作系统具有高度的稳定性、安全性和可定制性,能够与 Oracle 数据库良好地兼容。同时,Linux 系统提供了丰富的系统管理工具和监控手段,便于运维人员对服务器进行管理和维护。
-
安全配置
Oracle 数据库的安全至关重要,涉及数据的保密性、完整性和可用性。在部署过程中,需要进行全面的安全配置。首先,设置复杂的用户密码策略,要求密码长度、复杂度符合一定标准。对不同用户角色分配严格的权限,遵循最小权限原则,仅授予用户完成其工作职责所需的最低权限。启用审计功能,对数据库的关键操作(如用户登录、数据修改等)进行审计记录,以便在出现安全问题时进行追溯和调查。同时,加强网络安全防护,通过防火墙设置限制外部对数据库服务器的访问,仅允许合法的 IP 地址和端口进行连接。对传输中的数据进行加密,采用 SSL/TLS 等加密协议保障数据在网络传输过程中的安全性。
四、使用规范
本节主要介绍实践中的百胜Oracle最佳实践,并从表结构设计、索引设计、sql使用和应用规约等方面,描述百胜Oracle运维和使用规范。提高业务开发系统的规范性和代码的可读性,减轻维护工作量,提高工作效率。
-
对象命名规范
【原则】
- 命名建议使用具有意义的英文词汇,词汇中间以下划线_分隔
- 命名只能使用英文字母、数字、下划线
- 避免用Oracle的保留字如:group,order 等作为单个字段名
a.【建议】数据库命名规范
数据库名需具备一定的业务含义,以利识别与管理。建议依据业务、产品线或其他指标予以区分,通常不应超过 20 个字符。
如:临时库(tmp_crm)、测试库(test_crm)
b.【建议】表命名规范
- 同一业务或者模块的表尽可能使用相同的前缀,表名称尽可能表达含义
- 多个单词以下划线分隔,不推荐超过 32 个字符
- 建议对表的用途进行注释说明,以便于统一认识,如:临时表(tmp_xxx)、备份表(bak_xxx)
- 不同业务模块的表单独建立 DATABASE,并增加相应注释
c.【建议】字段命名规范
- 字段命名需要表示其实际含义的英文单词或简写
- 建议各表之间相同意义的字段应同名
- 字段也尽量添加注释,枚举型需指明主要值的含义,如”0 - 离线,1 - 在线”
- 布尔值列命名为 [is_描述]。如 member 表上表示为 enabled 的会员的列命名为 is_enabled
- 字段名不建议超过30个字符,字段个数不建议大于 80
- 尽量避免使用保留字,如 order、from、desc 等,请参考官方保留字
d.【建议】主键及索引命名规范
- 主键:pk_[表名称简写]_[字段名简写]
- 唯一索引:uk_[表名称简写]_[字段名简写]
- 普通索引:idx_[表名称简写]_[字段名简写]
- 多单词组成的 column_name,取尽可能代表意义的缩写
- 索引名不建议超过 32 个字符,上限 64 个字符
e.【建议】建表规范
- create table if not exists table_name 或者 drop table if exists table_name 语句建议增加 if 判断,避免应用侧由于表的改动造成的异常中断
- 每张表都建议定义主键,主键用于唯一标识表中的每一行记录,确保数据的完整性和唯一性。主键字段应选择具有唯一性且不允许为空的字段或字段组合
- 出于为性能考虑,尽量避免存储超宽表,表字段数不建议超过 80 个,建议单行的总数据大小不要超过 64K
- 分区表主键和唯一索引需要包含分区键
- 应避免使用外键,在应用端实现
f.【建议】索引设计规范
- 选择区分度大的列建立索引,不在低基数列上建立索引
- 单张表的索引数量控制在 5 个以内,建议优先考虑覆盖索引,避免冗余索引。
- 索引中的字段数建议不超过 5 个。
- 索引的总长度不超过 256 字节,否则过长可能会影响性能
- 尽量不要在频繁更新的列上创建索引
- 最左前缀原则,使用联合索引时,从左向右匹配
比如索引 idx_c1_c2_c3 (c1,c2,c3),相当于创建了 (c1)、(c1,c2)、(c1,c2,c3) 三个索引
where 条件包含上面三种情况的字段比较则可以用到索引
但像 where c1=a and c3=c 只能用到 c1 列的索引
像 c2=b and c3=c 等情况就完全用不到这个索引
- 定期删除一些长时间未使用过的索引
g.【建议】表及字段需要明确标注中文注释
表及字段均需标注中文注释,以便维护以及新员工熟悉业务。
h.【推荐】使用AL32UTF8 字符集
- 在创建数据库时,使用 AL32UTF8 字符集能够确保不同语言的字符都能正确存储和处理,避免因字符集不兼容导致的乱码问题
- 数据库字符集在创建后原则上不能随意更改
i.【强制】禁止创建大字段
如无特殊需求,应避免使用大字段(BLOB、CLOB、LONG、TEXT、IMAGE 等),因为大字段的存储和处理可能会消耗大量资源,影响数据库性能。
-
SQL语句规范
To do
a.【推荐】用 UNION ALL 而不是 UNION
UNION 会将两个结果集中的记录进行排除重复记录的操作
UNION ALL 没有这个操作,因此使用后者可以更快返回记录
在业务上没有特殊要求的时候,应该优先使用 UNION ALL
b.【推荐】SQL 文本不宜过长
SQL 文本过长时会造成 SQL 编译耗时长、内存使用增加
严重时,还可能导致数据库无法解析,甚至内存泄漏耗尽操作系统可用内存
因此,建议 OLTP 系统 SQL 文本长度不超过 2000 字节,OLAP 系统不超过 20000 字节
b.【推荐】用Where子句替换HAVING子句
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤.。这个处理需要排序,总计等操作。
d.【推荐】UPDATE 语句规范
禁止单条 SQL 语句同时更新多个表
UPDATE 应仅针对有修改的字段进行
UPDATE 操作时,应该做到仅对有修改的字段 UPDATE,避免对表中无修改的字段也一并更新,后者的做法将耗费更多的 CPU、内存
e.【推荐】GROUP BY 使用规范
- 建议为 GROUP BY 字段建索引
- GROUP BY 的列最好是整型,或者非常短的字符串,例如 VARCHAR(10)
- GROUP BY 的列不要计算, 例如禁止这样写 GROUP BY MOD(ID,5)
- HAVING 子句能写在 WHERE 条件中时,最好不要写到 GROUP BY 里面
例如:
select max(a),b from t group by b having max(a) > 1000
可以在 WHERE 条件中添加 a> 1000
select max(a),b from t where a>1000 group by b
Not to do
a.【强制】避免使用select * 语句
SELECT语句应只获取需要的字段,不建议使用SELECT *,且降低了使用覆盖索引的可能性。全表扫描在数据量较大时,会对数据库性能产生显著的负面影响,且降低了使用覆盖索引的可能性。为了避免全表扫描,应尽可能在 WHERE 子句中使用索引列进行条件筛选。
b.【强制】禁止对where条件对列进行函数或运算
在SQL语句中,应避免在where条件对列进行数学运算或函数运算,会导致相关索引无效,可能出现全表扫描。
例如:SELECT * FROM employees WHERE UPPER(last_name) = 'SMITH';
c.【强制】禁止where条件中使用模糊匹配:like 前置%
like查询只能使用前缀索引,因此要避免使用like '%abc',防止因为索引失效导致全表扫描。
d.【强制】避免使用嵌套查询
尽量避免在 SQL 语句中使用过于复杂的嵌套结构。深度嵌套的代码不仅难以理解和维护,还可能导致性能问题。建议将其分解为多个简单的查询
h【强制】where子句中禁止对字段进行null值判断
where条件中,应禁止对字段进行null值判断,否则会索引失效,导致全表扫描。
i【强制】where子句中避免使用!=或<>操作符以及not in
where条件中使用!=或<>以及not in,易造成索引失效,触发全表扫描
-
应用规约
To do
a.【推荐】提前规划好表的容量、大表做好数据归档策略
创建新表需要提前预估并规划表的容量大小,对于大表需要做好归档及清理策略,防止表过大影响数据库性能。
b.【推荐】账号命名建议
人用账号:xxx_dev(开发)、xxx_admin(管理员)
应用账号:xxxx_r(只读)、xxxx_w(读写)、xxxx_app(另一种读写)
Not to do
a.【强制】禁止在数据库中存放图片、二进制大文件
b.【强制】不修改主键
为避免数据页大量移动,禁止修改表的主键。
c.【建议】建议避免使用视图做业务相关的操作
视图的查询性能较差,同时基表结构变更,需要对视图进行维护,如果视图可读性差且包含复杂的逻辑,都会增加维护的成本。生产环境建议避免创建视图做业务相关操作,可用来作为日常查询和运维使用。
d.【建议】生产环境避免创建存储过程
在Oracle中不推荐使用存储过程,容易将业务与数据库耦合,增加系统复杂性,不利于扩展。存储过程在一定程度上也会使程序难以调试和拓展,各种数据库的存储过程语法相差很大,给将来的数据库移植带来很大的困难,且会极大的增加出现BUG的概率。
e.【建议】生产环境避免使用触发器
触发器难以开发和维护,不能高效移植,且在复杂的逻辑以及高并发下,容易出现死锁影响业务。
五、监控告警
-
监控维度
IT运维团队会基于以下KPI对Oracle进行监控和告警:
- 主机资源监控:CPU、内存、磁盘、网络
- Oracle服务指标:实例存活情况、主从复制情况、从库延迟状态、表空间使用情况
- Oracle性能指标:QPS、TPS、CPU开销、内存开销、网络开销、连接数
-
监控告警架构
Oracle目前正在对接百胜云监控体系,通过夜莺发送告警,并对核心指标提供监控大屏。
监控屏地址:Oracle数据库监控
-
服务等级
IT运维团队对Oracle的服务支持由DBA团队提供,服务等级定义同线上业务应用分级。
原则上Oracle的服务等级等于所属应用的分级。
六、常见问题处理
-
表空间存储不足
1.1 登录数据库
首先,你需要使用合适的权限登录到数据库。通常情况下,你可以使用Oracle的SQL*Plus工具或者其他数据库管理工具(比如Oracle SQL Developer)来连接数据库。
sqlplus sys as sysdba
1.2. 检查表空间使用情况
例:表空间TMS_TM_DATA存储空间不足
登录后,检查表空间TMS_TM_DATA的使用情况,确认其是否真的超过了80%。
SELECT
df.tablespace_name AS "Tablespace",
ROUND((df.total_space - fs.free_space) / df.total_space * 100, 2) AS "Used %"
FROM
(SELECT
tablespace_name,
SUM(bytes) / 1024 / 1024 AS total_space
FROM
dba_data_files
GROUP BY
tablespace_name) df,
(SELECT
tablespace_name,
SUM(bytes) / 1024 / 1024 AS free_space
FROM
dba_free_space
GROUP BY
tablespace_name) fs
WHERE
df.tablespace_name = fs.tablespace_name
AND
df.tablespace_name = 'TMS_TM_DATA';
1.3. 增加表空间大小
如果确认表空间确实接近或超过80%的使用率,可以通过增加数据文件的大小或者添加新的数据文件来扩展表空间。选择哪种方式取决于当前的数据库文件布局和存储容量。
ALTER TABLESPACE TMS_TM_DATA
ADD DATAFILE '/path_to_new_datafile/TMS_TM_DATA02.dbf' SIZE 500M;
将/path_to_new_datafile/TMS_TM_DATA02.dbf替换为新数据文件的路径,500M替换为文件的初始大小
1.4. 检查和确认
增加表空间后,再次检查表空间的使用情况,确保扩容操作成功,并且表空间的使用率已经降到安全范围内。
附录:Oracle数据库清单
| 系统 | 架构 | 版本 | 服务器类型 | 是否SOX | 备份规则 | 数据恢复预案 |
|---|---|---|---|---|---|---|
| EPM合并报告系统 | 单实例 | 11.2.0.3 | vm | 是 | 全备 0 0 7,21 * * /增备 0 0 2,4,10,12,16,18,20,22,26 * * | 备份集恢复 |
| ADG | 12.2.0.1 | vm | 否 | / | ||
| 12.2.0.1 | vm | 否 | / | |||
| TMS运输管理系统 | 单实例 | 12.1.0.2 | vm | 是 | 全备 0 2 7,21 * * /增备 0 2 2,10,18,26 * * | 备份集恢复 |
| WMS仓库管理系统 | RAC | 12.2.0.1 | 物理机 | 是 | 全备 0 2 5,21 * *增备 0 2 2,10,18,26 * * | 备份集恢复 |
| EP 供应链管理 | 单实例 | 12.2.0.1 | vm | 否 | / | |
| JDE特斯拉系统 | RAC | 19.16.0.0 | 一体机 | 是 | / | |
| PS人事管理系统 | RAC | 12.2.0.1 | 一体机 | 是 | 全备 0 0 7,21 * * /增备 0 0 2,4,10,12,16,18,20,22,26 * * | 备份集恢复 |