自己挖坑自己填——某某人如是說。依稀記得兩年前冬去春來的時節,某某人給自己挖了一個小小的坑。歲月輪轉,兩年的光景,灑家來填坑了。
2017年剛剛立春,分公司服務平台准備部署上線,由於當時服務器資源緊張,數據庫要和網站、商城共用一台服務器,這台服務器是Linux操作系統。當時平台組也比較忙,於是乎在對Linux一知半解,對Oracle一知半解的情況下硬着頭皮在生產環境安裝並創建了人生中第一個Linux下的Oracle數據庫,也挖了今天要填的坑。
1、 對Linux文件系統不熟,沒有關注磁盤分區情況,直接在默認分區下安裝了Oracle,並創建了實例,該分區只有50G,當時還剩多少沒注意。
2、 在后續使用過程中沒有為項目單獨創建表空間,直接使用了默認表空間,造成SYSTEM、USERS、SYSAUX表空間越來越大。
3、 后來網站和商城外包開發,他們直接用了我們這個項目的Oracle實例,作為這個實例的一個用戶存在,此時我依然沒有考慮到空間問題。
4、 后來同事也曾經反映過磁盤空間的問題,因為項目沒上量,就直接歸咎到網站和商城外包公司那邊了,讓他們做了清理。
2019年立春還有一個多月,新項目和服務平台共用一個數據庫,做數據遷移時終於發現了空間問題。
1、 Oracle所在分區磁盤空間緊張,還剩不到6G。
2、 SYSTEM、USERS、SYSAUX表空間占用率太高,TEMP表空間已滿。圖上SYSTEM是擴容過的,沒擴之前忘記截圖了,擴了2G。
新項目上線,隨着使用量上升,空間終究是個問題,因此查了查資料,在磁盤分區擴容和表空間轉移兩個方案中選擇了把表空間轉移到新的磁盤分區。具體思路及操作步驟如下:
思路:根據第一個圖可知還有home分區還很大,可以在這個分區上創建新的表空間文件,然后把現有的數據表的表空間換成新的表空間,這樣既可以清理出來root分區磁盤空間,也規范了以后建表使用的表空間文件。實施之前先做了個小實驗,在原來表空間上創建了60萬記錄的表,這個時候USERS表空間變大,然后再把該表遷移到新的表空間,USERS表空間變小了。
一、第一步:使用root用戶在新的分區上創建存放Oracle表空間的目錄,並為Oracle用戶分配目錄權限。
第一次從root用戶切換到orauser用戶時,標識符變成了這個:
Linux下一些用到的命令如下:
l 創建目錄:mkdir 目錄名
l 為用戶分配目錄權限:chown -R 用戶名 目錄名
chmod -R 755 目錄名
注意:分配權限時目錄名前加“/”,代表根目錄
l 查看當前用戶所屬用戶組:groups
l 查看目錄文件命令:ls –lhi
l 文件讀寫屬性:在上圖中文件-rw—代表的是文件讀寫和執行的屬性,r表示可讀,w表示可寫,還有一個上圖沒有出現的x表示可執行。這個串一共10位,第一位代表類型,如果是d代表是目錄,第2到10位分三組分別代表所有者(user)、群組(group)、其他人(other)的權限。rwx-用數字表示的話分別是:r=4,w=2,x=1,-=0,每一組的三個位置上用數字代替相加后就是這一組的權限數字,例如rwxr-xr-x,第一組rwx就是4+2+1=7,第二組和第三者r-x就是4+0+1=5,因此rwxr-xr-x用數字代表就是755,表示只有所有者才有讀寫執行的權限,組群和其他人只有讀和執行的權限。上面介紹為用戶分配目錄權限的時候“chmod -R 755 目錄名”中的755就是這個意思。
二、第二步:新分區上目錄名創建好后,開始創建新的數據庫表空間。創建之前,先看看表空間使用情況和表空間所在路徑。
l 查詢表空間所在路徑:select * from dba_data_files
l 查看表空間使用情況的SQL:
SELECT D.TABLESPACE_NAME,
SPACE || 'M' "SUM_SPACE(M)",
BLOCKS "SUM_BLOCKS",
SPACE - NVL (FREE_SPACE, 0) || 'M' "USED_SPACE(M)",
ROUND ( (1 - NVL (FREE_SPACE, 0) / SPACE) * 100, 2) || '%'
"USED_RATE(%)",
FREE_SPACE || 'M' "FREE_SPACE(M)"
FROM ( SELECT TABLESPACE_NAME,
ROUND (SUM (BYTES) / (1024 * 1024), 2) SPACE,
SUM (BLOCKS) BLOCKS
FROM DBA_DATA_FILES
GROUP BY TABLESPACE_NAME) D,
( SELECT TABLESPACE_NAME,
ROUND (SUM (BYTES) / (1024 * 1024), 2)
FREE_SPACE
FROM DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME) F
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME(+)
UNION ALL
SELECT D.TABLESPACE_NAME,
SPACE || 'M' "SUM_SPACE(M)",
BLOCKS SUM_BLOCKS,
USED_SPACE || 'M' "USED_SPACE(M)",
ROUND (NVL (USED_SPACE, 0) / SPACE * 100, 2) || '%'
"USED_RATE(%)",
NVL (FREE_SPACE, 0) || 'M' "FREE_SPACE(M)"
FROM ( SELECT TABLESPACE_NAME,
ROUND (SUM (BYTES) / (1024 * 1024), 2) SPACE,
SUM (BLOCKS) BLOCKS
FROM DBA_TEMP_FILES
GROUP BY TABLESPACE_NAME) D,
( SELECT TABLESPACE_NAME,
ROUND (SUM (BYTES_USED) / (1024 * 1024), 2)
USED_SPACE,
ROUND (SUM (BYTES_FREE) / (1024 * 1024), 2)
FREE_SPACE
FROM V$TEMP_SPACE_HEADER
GROUP BY TABLESPACE_NAME) F
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME(+)
ORDER BY 1;
三、第三步:創建表空間:分別創建數據表空間和索引表空間,數據表空間創建了2個,日志單獨放一個表空間,其他業務數據放一個表空間。另外給SYSTEM和TEMP擴展一個表空間文件
l 以sysdba身份啟動sqlplus
命令行:sqlplus / as sysdba
l 創建表空間語句:
create tablespace 表空間名稱 datafile '表空間文件名(帶路徑)' size 5120M autoextend ON next 100M maxsize unlimited extent management local;
l SYSTEM表空間增加數據文件:
alter tablespace system add datafile '/home/oradata/system_01.dbf' size 2048M;
l TEMP表空間增加數據文件:
alter tablespace temp add tempfile '/home/oradata/temp_01.dbf' size 2048M;
這里還有兩個小坑,SYSTEM和TEMP表空間創建后,不是自動擴展,需要修改,修改后還要改增長步長,默認步長都是1。因此,任何交易類操作做完后一定要看結果,一定要看結果,一定要看結果。
alter database datafile '/home/oradata/system_01.dbf' autoextend on next 10M maxsize 20480M;
alter database tempfile '/home/oradata/temp_01.dbf' autoextend on next 10M maxsize 20480M;
設置原來表空間停止自動擴展
alter database datafile '表空間文件' autoextend off;
alter database tempfile '表空間文件' autoextend off;
l SYSTEM表空間為什么會滿?
查詢該表空間哪個表最大:
select * from (select SEGMENT_NAME,sum(bytes)/1024/1024 sx from dba_segments
where tablespace_name='SYSTEM' group by segment_name)
where sx>100 order by sx desc;
查看審計表AUD$,審計(Audit)用於監視用戶所執行的數據庫操作
select count(*) from SYS.AUD$;
查看那種審計比較多:
select action_name,count(*) from dba_audit_trail group by action_name;
對於審計這個表,可以擴展系統表空間的大小,也可以關閉審計功能,並truncate掉這張表。
l USERS表空間為什么會這么大
業務表沒有單獨創建表空間是一個原因,但其實現在數據記錄條數並沒有那么大,最多也就是百萬級,查看一下USERS表空間哪個表占的比較大:
上網搜了下SYS_LOB0000136691C00006$$,是因為CLOB字段的問題,通常情況下普通表只會新增一個或兩個段對象,有CLOB字段的表CLOB列額外新增了兩個段對象,類型為LOBSEGMENT和LOBINDEX,LOBINDEX用於指向CLOB段,找出其中的某一部分,所以存儲在表中的CLOB存儲的是一個地址,或者說是一個指針,實際上表中的CLOB列中存的是一個地址段.然后在lobindex找到所有的地址段.然后在lobSegment中把所有地址段的值都讀取了來。所以lobSegment就保存了CLOB列的真正的數據,所以會非常大,並且獨立於原始表存在
四、第四步:將新項目的表遷移到新的表空間
l 更換表空間的語句:alter table 表名 move tablespace 表空間名;
l 如果是整個表空間的表都要轉到新的表空間則用這個語句:
select 'alter table ' ||table_name || ' move tablespace 目標表空間名稱;' from user_all_tables where tablespace_name='源表空間名稱'
l 因為這次要把項目用到的表從USERS換到新的表空間,不是所有表,因此可以通過用戶來批量修改。
l 根據用戶查數據表:
select * from all_tables where owner = '用戶名'; 注意大小寫。
l 最終轉換表空間語句:select 'alter table ' ||table_name || ' move tablespace 目標表空間名稱;' from all_tables where upper(owner)=upper('用戶名');
五、第五步:使用move后,索引會變的無效,需要重建索引
查找用戶下的所有索引,看看索引狀態
select index_name,table_name,tablespace_name,index_type,status from dba_indexes where table_owner='用戶名' ;--注意大小寫
找到索引狀態無效的進行重建:
alter index 用戶名.索引名稱 rebuild tablespace 表空間名;
六、第六步:把CLOB自動轉移到相應的表空間(雖然數據表轉到新的表空間了,但CLOB字段沒有自動轉)
ALTER TABLE 用戶名.表名 MOVE LOB(CLOB字段名) STORE AS (TABLESPACE 新表空間);
注意新建的表空間一定要足夠大。
七、第七步:修改用戶默認表空間
ALTER USER 用戶名 DEFAULT TABLESPACE 表空間;
八、第八步:收縮USERS表空間數據文件
l 先找到USERS表空間數據文件的路徑或者ID,這里用了路徑名
select * from dba_data_files;
l 允許表空間進行收縮(對表空間進行融合)
alter tablespace users coalesce;
l 查詢表空間中有哪些表
select * from dba_segments where tablespace_name='USERS' and segment_type='TABLE'
l 允許表進行行移動(某些表不能進行truncate,只能delete)
alter table SCOTT.DEPT enable row movement;
alter table SCOTT.EMP enable row movement;
alter table SCOTT.SALGRADE enable row movement;
l 對表進行高水位線回收
alter table SCOTT.DEPT shrink space;
alter table SCOTT.EMP shrink space;
alter table SCOTT.SALGRADE shrink space;
l 收縮表空間數據文件大小
alter database datafile '/ora/app/oradata/fwzs/users01.dbf' resize 2048M;
九、第九步:執行完畢后,確認結果:數據能夠正常使用,root分區空間釋放。