简介:这份文档面向 Oracle 数据库运维与开发人员,针对归档日志空间耗尽引发的 ORA-00257 错误,梳理从现象判断、空间占用核查到物理文件清理与 RMAN 逻辑空间释放的完整处理思路,适合需要快速定位归档日志满故障并恢复数据库可用性的技术人员参考。资源包共 1 个 doc 文件,大小约 76KB,正文以操作记录、命令说明和注意事项为主,篇幅精炼,便于在故障现场按条目查阅关键语句。目前已有 580 人学习,说明其在 Oracle 归档日志故障处置场景中具有一定参考价值。文档不仅给出处理顺序,还强调选择性删除日志、用 crosscheck 标记 expired、再删除过期归档等易错点,并配有空间占用比例与释放结果的图示,可帮助读者理解物理清理与逻辑释放之间的配合关系,逐步建立可复用的归档日志满排错路径。
1. ORA-00257 归档日志满:先看懂 89.78% 这个数字再动手
很多现场是这样:监控先报数据抽取任务超时,等登进库,ORA-00257 归档日志满的报错已经在 alert log 里刷了一阵,v$flash_recovery_area_usage里 ARCHIVELOG 那一行显示 89.78%,日志切换卡住,后面的 DML 全排队。Oracle 的 archivelog 机制本来是为了保证可恢复性,把每次变更都落一份归档,但归档写不进去的时候,数据库会先挂住归档进程,再挂住业务。
手头这份文档给的就是一条最短处置路径:删物理归档文件,再用 RMAN 的crosscheck和delete expired把逻辑空间收回来。它适合两类人:正在处理告警、需要立刻腾出空间的运维和 DBA;以及手上这套库备份窗口没算清楚、想提前把处置流程捋顺的人。命令本身不难,难的是别把「腾空间」做成「破坏可恢复性」。
2. 看懂 FRA 与 archivelog:两个查询把空间账算清
动手之前先把账算清楚,否则很容易出现「文件删了、空间没降、任务还在停」的尴尬。这一章拆两个查询:一个看 FRA 里各类文件各占多少,一个把参数里的逻辑路径和磁盘上的真实目录对上。
2.1 v$flash_recovery_area_usage 的四个字段怎么读
原文第一条命令就是查这个视图,但很多人只看PERCENT_SPACE_USED一列,其余三列直接略过,结果判断失误。
set lines 200 pages 100 col file_type format a25 select file_type, percent_space_used, percent_space_reclaimable, number_of_files from v$flash_recovery_area_usage order by percent_space_used desc;逻辑说明:这条语句按占用比例倒序列出 FRA 内的文件类型,ARCHIVELOG一般排在最前面,其次是BACKUP PIECE、CONTROLFILE、ONLINELOG、FLASHBACK LOG。有些版本上这个视图叫v$recovery_area_usage,字段一致,查不到时换个名字再试一次即可。
参数说明:
PERCENT_SPACE_USED:该类文件占db_recovery_file_dest_size的百分比。原文的 89.78 就是这一列。PERCENT_SPACE_RECLAIMABLE:可以通过删除 obsolete/expired 记录回收的比例,也就是「账面上还能挤出来多少」。如果这个数字很小而 used 很高,说明可回收余量已经不多,光删文件救不了,得考虑扩容或改保留策略。NUMBER_OF_FILES:文件个数,配合后面的目录ls能快速判断是不是某一两天的归档异常膨胀。
实际判断时,我会把PERCENT_SPACE_USED和PERCENT_SPACE_RECLAIMABLE相加看一眼:接近 100% 说明 FRA 里几乎没有冗余可清,处置动作要更激进一些;如果 reclaimable 还有二三十个点,说明主要是控制文件里的历史记录没清,crosscheck+delete expired就能吃下一大块。
再看v$recovery_file_dest,它给出的是空间上限和已用量的绝对值:
col name format a30 select name, space_limit/1024/1024/1024 as limit_gb, space_used/1024/1024/1024 as used_gb, space_reclaimable/1024/1024/1024 as reclaimable_gb, number_of_files from v$recovery_file_dest;这条的价值在于换算成 GB 之后,你能直接和df -h的磁盘余量对上。SPACE_LIMIT是 Oracle 自己设的逻辑上限(也就是db_recovery_file_dest_size),不是磁盘容量;磁盘满了但 Oracle 只用到 60%,照样会出问题,这个坑在第 5 章单独说。
2.2 show parameter recover 的输出怎么对应到物理路径
原文用show parameter recover找日志存放路径和空间大小,这个写法是模糊匹配,会把所有名字里带recover的参数都列出来。
show parameter recover输出里真正有用的是三行:db_recovery_file_dest(FRA 根目录,原文是/backup/flash_recovery_area)、db_recovery_file_dest_size(逻辑上限,原文是 160G)、log_archive_dest_n(如果归档不走 FRA,这里会指向别的路径)。想看得更准,直接查参数视图:
col name format a35 col value format a60 select name, value from v$parameter where name in ('db_recovery_file_dest', 'db_recovery_file_dest_size', 'log_archive_dest_1', 'log_archive_format');再补一条archive log list,确认归档模式、归档目标和当前日志序列:
archive log list这一步容易被跳过,但它决定了你待会儿删的到底是主库归档还是备库归档。Archive Mode显示ARCHIVELOG说明归档已开;Destination如果显示USE_DB_RECOVERY_FILE_DEST,归档才真正落在 FRA 目录下。如果log_archive_dest_1指向自定义路径,那 FRA 里的占用和归档增长就不是一回事,删错目录白忙一场。
还有一个隐藏情况:多实例或 RAC 环境,FRA 目录下会按实例名分thread_1、thread_2子目录。删之前先ls看清结构,别把一个实例的归档删干净、另一个实例的还留着,最后仍然切换不过去。
2.3 89.78% 是告警线,不是删除线
看到PERCENT_SPACE_USED高就动手删,是新手最容易踩的一步。归档增长速度决定了你有多少时间,这个数据要自己算。
select trunc(first_time) as day, count(*) as cnt, round(sum(blocks * block_size) / 1024 / 1024 / 1024, 2) as gb from v$archived_log where first_time > sysdate - 7 and deleted = 'NO' group by trunc(first_time) order by 1;逻辑说明:按天统计最近七天归档的生成量和文件数,deleted = 'NO'只算还在 FRA 里的。这条语句能直接回答两个问题——每天归档涨多少 GB、按当前db_recovery_file_dest_size还能撑几天。
参数说明:blocks * block_size是单个归档文件的大小,求和后换算成 GB;trunc(first_time)按自然日分组。如果发现某一天的量是平时的三倍,先查是不是有大批量导入、索引重建或者日志切换过于频繁(比如log_checkpoint_interval设置不合理、日志文件太小),这种增长不是删归档能解决的。
判断标准我一般这样定:使用率低于 70% 不处理,只做记录;70% 到 85% 之间开始准备清理,同时确认备份是否覆盖;超过 85% 就是紧急,得按第 4 章的流程走一遍。原文的 89.78% 已经属于「再晚一点就要挂」的区间,这时候业务侧通常已经有感知了,所以处置顺序要稳,不能一上来就rm -rf。
3. 删除策略选型:OS rm、delete expired 与 delete archivelog 的边界
同样叫「删归档」,三种做法对可恢复性的影响完全不一样。原文的思路是先删物理文件、再进 RMAN 清逻辑记录,这个组合在特定场景下是对的,但它不是默认方案。这一章把三条路径摆在一起比,再说清楚什么条件下能走原文那条。
3.1 三条删除路径的对比与适用边界
| 路径 | 命令 | 删物理文件 | 更新控制文件 | 适用场景 |
|---|---|---|---|---|
| OS 层删除 | rm -rf /backup/.../archivelog/2024_06_10 | 是 | 否,必须补 crosscheck | FRA 已满、需要立刻腾空间 |
| RMAN 清失效 | crosscheck archivelog all+delete expired archivelog all | 否 | 是,清掉已不存在的记录 | 配合 OS 删除,把账做平 |
| RMAN 直接删 | delete archivelog until time 'sysdate-7' | 是 | 是 | 归档已备份、按保留策略清理 |
原文走的是第一条加第二条的组合:先用rm把物理文件拿掉,再用crosscheck把控制文件里的记录标成EXPIRED,最后delete expired把记录清掉,FRA 的占用才真正降下来。
第三条是 RMAN 的「正规」做法,一步到位删物理文件也删记录,但它有一个前提——这些归档已经备份过,或者你根本不需要它们。如果没备份就直接delete archivelog all,等于把可恢复性一起删了,这在生产库上是严重事故。
原文敢把某个日期目录整个删掉,是因为「这是新的数据库服务器,没有其他的操作记录」。这句话是整份文档里最关键的一句限定条件,脱离了它就不能照抄。生产库上我一般按时间窗口删,保留最近 3 到 7 天,并且删之前确认这几天的归档已经进过备份集。
3.2 用 list archivelog 和 report obsolete 摸清家底
进 RMAN 之后别急着删,先看清楚控制文件里到底记了什么。
rman target /list archivelog all; list expired archivelog all; report obsolete;逻辑说明:list archivelog all列出控制文件里登记的全部归档,包括物理文件已经不存在的;list expired archivelog all只列已经标记为失效的;report obsolete按当前保留策略报告哪些备份已经过期、可以删。这三条命令加起来,能区分「账上有、磁盘上没有」和「账上有、磁盘上也有」两类文件。
参数说明:list archivelog all输出很长,可以加summary只看汇总:list archivelog all summary;。想看某段时间的,用list archivelog from time 'sysdate-7' until time 'sysdate';。
如果list expired archivelog all已经有一堆输出,说明之前有人删过物理文件但没做crosscheck,控制文件里的记录还挂着,这时候直接delete expired就能回收一部分空间,连rm都省了。反过来,如果list expired是空的,而 FRA 又确实快满了,那说明空间是被真实存在的归档占着,必须删物理文件或者扩容。
3.3 保留策略、备份窗口与 db_recovery_file_dest_size 的联动
FRA 反复满,根因往往不在归档本身,而在保留策略和备份窗口没对齐。归档要留多久,取决于你能接受恢复到哪个时间点;备份多久跑一次,决定了归档什么时候可以安全删除。这两件事不定,删多少次都是治标。
先看当前策略:
show retention policy; show archivelog deletion policy;如果输出是CONFIGURE RETENTION POLICY TO REDUNDANCY 1,意思是保留一份冗余,配合report obsolete就能自动算出哪些可以删。恢复窗口模式更直观:
configure retention policy to recovery window of 7 days;这条的意思是保证任意时间点都能恢复到 7 天内的状态,RMAN 会据此判断哪些归档和备份还不能删。设置完之后再跑report obsolete,看到的就是真正可以清理的清单。注意这条命令只影响 RMAN 的判断,不会自动删东西,删除动作仍然要显式执行delete obsolete。
空间上限这边,能调就调,但要先看磁盘:
df -h /backupalter system set db_recovery_file_dest_size = 300G scope = both;参数说明:scope = both表示同时改内存和 spfile,重启后仍然生效;如果只写scope = memory,实例重启就回到旧值,等于白改。调大之前必须确认/backup所在文件系统有足够余量,db_recovery_file_dest_size超过物理磁盘容量,Oracle 不会拦你,但写到一半磁盘满会报更难看懂的错误。
我的习惯是把db_recovery_file_dest_size设为磁盘可用空间的 70% 左右,留三成给控制文件、闪回日志和其他临时文件;同时把归档删除做成定时任务,让使用率长期稳定在 60% 以下。这样即使某天归档暴涨,也有缓冲时间,不至于业务先挂。
4. 从 sqlplus 到 RMAN:一次可复现的归档空间回收流程
这一章把原文的步骤按现场顺序重排一遍,每一步都给出可执行命令和失败时的观察点。整套流程适用于「FRA 已接近满、归档物理文件确认可删、备份已覆盖」的场景,新库或者刚上线还没有业务写入的库可以直接照做;生产库要把删除范围收窄到具体日期。
4.1 第一步:确认空间水位与归档路径
先切到 Oracle 用户,用sysdba本地登录,不经过监听,避免因监听异常连不上而耽误时间。
su - oracle sqlplus / as sysdba登录后先把三个关键信息打出来:
set lines 200 pages 100 col file_type format a25 select file_type, percent_space_used, percent_space_reclaimable, number_of_files from v$flash_recovery_area_usage; show parameter db_recovery_file_dest show parameter db_recovery_file_dest_size archive log list逻辑说明:第一条确认ARCHIVELOG的占比,也就是原文的 89.78%;后两条把 FRA 根目录和逻辑上限打出来,和磁盘上的实际路径核对。archive log list用来确认归档模式以及归档是否真的落在 FRA。
参数说明:如果show parameter db_recovery_file_dest输出的VALUE是空,说明 FRA 没启用,归档走的是log_archive_dest_n指定的路径,这时候要按那个路径去删,而不是去/backup/flash_recovery_area。这一步判断错,后面全白做。
观察点:如果v$flash_recovery_area_usage查询很慢甚至报错,说明控制文件读写已经很吃力,先把处置动作简化,优先腾空间,别再做复杂统计。
4.2 第二步:物理归档文件的安全删除
到操作系统层看目录结构,别上来就rm -rf。
cd /backup/flash_recovery_area ls -l du -sh */archivelog/* 2>/dev/null | sort -h | tail -20逻辑说明:ls -l看 FRA 根目录下的实例目录;du -sh按日期子目录统计大小并排序,末尾几行就是占用最大的那几天。这一步的目的是确认「哪几天可以删」,而不是「全部删掉」。
原文的操作是进入/backup/flash_recovery_area下,删掉2012_06_10、2012_06_11两个日期目录。生产环境我一般保留最近 3 天,先列出待删清单再执行:
# 先列出目标,确认范围和时间 find /backup/flash_recovery_area -type d -path '*archivelog*' -name '2024_06_*' # 确认无误后按日期目录删除 rm -rf /backup/flash_recovery_area/ORCL/archivelog/2024_06_10 rm -rf /backup/flash_recovery_area/ORCL/archivelog/2024_06_11参数说明:-path '*archivelog*'限定只匹配归档目录,避免误伤同级的backupset、controlfile;-name '2024_06_*'按日期匹配,这里要换成你现场的实际目录命名。执行rm之前务必用ls看一眼目录内容,确认里面是.arc、.dbf之类的归档文件,而不是备份片。
观察点:删完之后df -h应该立刻看到磁盘空间释放,但v$flash_recovery_area_usage里的数字大概率不动,这是正常的,账还没平,下一步处理。
如果库运行在 ASM 上,OS 层根本看不到这些文件,要用asmcmd:
export ORACLE_SID=+ASM asmcmdls +FRA/ORCL/ARCHIVELOG/2024_06_10/ rm +FRA/ORCL/ARCHIVELOG/2024_06_10/thread_1_seq_1234.256.1234567890参数说明:ASM 里没有「目录整删」的便捷写法,rm要指名到文件,或者用rm -rf删整个目录(部分版本支持)。文件名里的thread_1_seq_1234表示线程 1、序列号 1234,删之前确认这些序列号确实已备份。
4.3 第三步:RMAN crosscheck 与 delete expired
物理文件没了,控制文件里的记录还在,这一步就是让两边对齐。
rman target /crosscheck archivelog all;逻辑说明:crosscheck会逐条读控制文件里的归档记录,去文件系统比对,物理文件不存在的标记为EXPIRED,存在的标记为AVAILABLE。原文说「进行文件查看,将已删除的日志标识成 expired」,说的就是这个动作。
参数说明:归档数量多的时候,crosscheck会跑很久,几分钟到几十分钟都有可能,主要开销在文件系统比对。它会持有控制文件的短期锁,但不会阻塞业务 DML,业务高峰期做问题不大,只是慢。如果想缩小范围,可以写crosscheck archivelog from time 'sysdate-7';。
然后清掉失效记录:
delete expired archivelog all;原文提示「输入 YES 即可」,这是 RMAN 的确认提示。想跳过确认,加noprompt:
delete noprompt expired archivelog all;参数说明:delete expired删的是控制文件里的记录,不是物理文件——物理文件在上一步已经删掉了。这条命令执行完,v$flash_recovery_area_usage里的PERCENT_SPACE_USED才会下降。很多人卡在这里,以为空间没释放是命令没生效,其实是漏了crosscheck,记录没被标成EXPIRED,delete expired自然一条都匹配不上。
观察点:如果delete expired报RMAN-08137之类的错误,通常是归档还需要传到备库或者需要备份,先确认 Data Guard 配置和备份状态再处理,别强删。
4.4 第四步:验证空间回收与业务恢复
回到 sqlplus 再查一次,确认数字降下来了:
select file_type, percent_space_used, percent_space_reclaimable, number_of_files from v$flash_recovery_area_usage; select name, space_limit/1024/1024/1024 as limit_gb, space_used/1024/1024/1024 as used_gb, number_of_files from v$recovery_file_dest;逻辑说明:第一条看比例,第二条看绝对值和文件数。SPACE_USED应该明显下降,NUMBER_OF_FILES也应该减少。两条数据对得上,才算真正回收成功。
再确认日志切换恢复正常:
alter system switch logfile;select sequence#, first_time, applied from v$archived_log where first_time > sysdate - 1/24 order by sequence# desc;参数说明:sysdate - 1/24是最近一小时,1/24表示一天二十四分之一。切换一次日志后,如果新序列号能正常出现在v$archived_log里,说明归档链路已经通了。
最后看 alert log 有没有新的 ORA-00257,以及业务侧的数据抽取任务是否恢复。原文提到「占满时候数据抽取任务停止」,这类任务通常有重试机制,空间释放后会自动恢复;如果没恢复,需要手动重启任务进程,别只盯着数据库。
5. 避坑与排查:五条让 ORA-00257 反复找上门的现场记录
这一章的五条都是「按文档做过一遍、过几天又满」的典型。每条按现象、原因、解决三步写,遇到对应症状直接对号入座。
5.1 rm 完文件,FRA 占用比例一动不动
现象:按流程删了2024_06_10目录,df -h显示磁盘空间释放了十几个 G,但v$flash_recovery_area_usage里ARCHIVELOG还是 89%,业务照样报 ORA-00257。
原因:FRA 的占用统计来自控制文件里的归档记录,不以磁盘实际文件为准。物理文件删了、记录没删,Oracle 认为空间还被占着,自然会拒绝新的归档写入。原文把crosscheck和delete expired放在删除之后,就是为了补这一步。
解决:进 RMAN 执行crosscheck archivelog all;再delete noprompt expired archivelog all;。如果执行完比例还是不动,用list expired archivelog all;确认记录是否真的被标成EXPIRED;没有的话,八成是db_recovery_file_dest路径和实际删除路径不一致,回去核对第 4.1 步的输出。
5.2 ASM 环境用 OS 的 rm 删归档
现象:登到数据库服务器,cd /backup/flash_recovery_area发现目录是空的或者根本不存在,ls看不到任何归档文件,但数据库里明明有归档在生成。
原因:库跑在 ASM 上,归档文件存在+FRA磁盘组里,操作系统层面看不到。这时候用find找、用rm删,要么找不到,要么删到别的文件。
解决:确认存储方式,show parameter db_recovery_file_dest如果输出是+FRA开头,就走asmcmd:ls +FRA/ORCL/ARCHIVELOG/看日期目录,rm删具体文件,删完同样要进 RMAN 做crosscheck和delete expired。ASM 里删文件建议先ls确认序列号,别用通配符一把梭。
5.3 直接 delete archivelog all,把没备份的归档删了
现象:嫌 OS 删加 crosscheck 麻烦,直接在 RMAN 里敲了delete archivelog all;,空间是下来了,过两天要做恢复演练,发现需要的归档没了,报RMAN-06025。
原因:delete archivelog all会同时删物理文件和控制文件记录,不做任何备份检查。原文之所以敢整目录删,是因为那是新库、没有业务记录。生产库上没备份就删,等于主动放弃可恢复性。
解决:删之前先确认备份覆盖,list backup of archivelog all;看最近一次备份的时间点;需要保留的,用delete archivelog all completed before 'sysdate-7';按时间窗口删,或者加backed up 1 times to device type disk限定只删已备份过的。养成习惯:任何delete之前先跑一遍list。
5.4 只调大 db_recovery_file_dest_size,不改归档策略
现象:告警来了就把db_recovery_file_dest_size从 160G 调到 300G,管了半个月又满,再调到 500G,磁盘先撑不住了。
原因:参数只是把天花板抬高,归档生成速度一点没变。日志切换频繁、大批量写入、备份没覆盖归档,这些根因不解决,调多大都会满。更糟的是,调大之后磁盘余量被吃掉,其他文件写不进去会报更隐蔽的错误。
解决:调大空间的同时做三件事——确认log_archive_dest_1没配多余的目标、检查日志组大小和切换频率(select group#, bytes/1024/1024 from v$log;)、把归档删除纳入定时任务(见第 6 章)。空间上限的设置原则是留出磁盘三成余量,不是越大越好。
5.5 备库还没收到归档,主库这边先删了
现象:主库清理完归档,Data Guard 备库第二天报 gap,v$archive_gap里有一串序列号补不上,备库延迟越来越大。
原因:主库删归档之前没确认备库的接收和应用进度。归档传输有延迟,主库看着「已经旧了」的归档,备库那边可能还没收到,删掉就再也补不回来,只能重建备库或者从备份里捞。
解决:删之前查一下备库的applied状态,select max(sequence#) from v$archived_log where applied = 'YES';,主库删除的序列号必须小于这个值。Data Guard 环境下我一般把删除动作放在备库确认之后,或者用 RMAN 的delete archivelog all completed before 'sysdate-2'留出足够缓冲,别贴着时间线删。
6. 把处置变成巡检:三个水位阈值与一份 cron 脚本
ORA-00257 处理一次不麻烦,麻烦的是同一个库一年处理五次。把第 2 章的查询和第 4 章的流程固化下来,做成常态巡检,才是真正省事的部分。
我一般按三个水位设阈值,动作各不相同:
| 使用率 | 级别 | 动作 |
|---|---|---|
| 70% 以下 | 正常 | 记录趋势,每周看一眼 |
| 70% 至 85% | 预警 | 确认备份覆盖,准备清理窗口 |
| 85% 以上 | 紧急 | 按第 4 章流程处置,当天完成 |
巡检脚本的核心就一条查询加一个判断,放在 cron 里每天跑两次:
#!/bin/bash # fra_check.sh - FRA 使用率巡检,超过阈值输出告警 export ORACLE_SID=ORCL export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1 export PATH=$ORACLE_HOME/bin:$PATH export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS' THRESHOLD=85 USED=$(sqlplus -s / as sysdba <<'EOF' set heading off feedback off pages 0 trimspool on select round(max(percent_space_used), 2) from v$flash_recovery_area_usage; exit EOF ) echo "$(date '+%F %T') FRA used: ${USED}%" if [ "$(echo "$USED > $THRESHOLD" | bc)" -eq 1 ]; then echo "WARN: FRA usage ${USED}% exceeds ${THRESHOLD}%, check archivelog immediately" fi逻辑说明:脚本以sysdba本地登录,取出v$flash_recovery_area_usage里的最大占用比例,和阈值比较后输出告警。bc用来做浮点比较,纯 shell 的-gt只支持整数,89.78 这种值会判断错误。
参数说明:ORACLE_SID、ORACLE_HOME要换成现场的值,cron 环境不会自动加载.bash_profile,这两个变量必须显式写;NLS_DATE_FORMAT是防止某些查询因日期格式报错;trimspool on去掉 sqlplus 输出的尾部空格,避免比较时出问题。
告警只是第一步,真正减少重复劳动的是把「确认可删范围」也写成固定查询:
select sequence#, thread#, name, first_time, round(blocks * block_size / 1024 / 1024 / 1024, 2) as gb from v$archived_log where deleted = 'NO' and first_time < sysdate - 3 order by first_time;这条列出三天前还在 FRA 里的归档,配合list backup of archivelog all;的输出,就能判断哪些已经进过备份、可以安全清理。我一般把这条查询和备份完成时间放在一张表里比对,备份覆盖到哪天,归档就删到哪天,不多删也不少删。
有个细节值得单独说:crosscheck之后再删,控制文件里的记录会少一截,但v$archived_log的历史统计也会跟着变。如果团队有归档增长趋势的报表,建议在清理前先把近三十天的数据导一份出来,否则趋势图会出现一个断崖,后面复盘时容易误判成业务量下降。
从那以后,我每次接手一套 Oracle,都会先把 FRA 的容量水位、归档删除策略和备份任务这三件事画在一张表上核对一遍,确认「备份覆盖到哪天、归档留到哪天、空间还能撑几天」三个数字能对上,再去动任何删除命令。这套习惯比记住多少条命令都管用,因为 ORA-00257 从来不是一条命令的问题,而是三个数字没对齐的结果。希望帮到你。
本文还有配套的精品资源,点击获取