DBA 常需要知道某個具體 Data File (數據文件) 裡存放了哪些 Table、Index、LOB 等段,以及各段佔用空間大小,以便規劃表空間擴容、移動大對象、檢查碎片。關鍵在於 DBA_EXTENTS 視圖記錄了每個 Extent 所屬的 File ID、Segment、Size。
SELECT e.segment_type AS segment_type,
e.segment_name AS segment_name,
f.file_name AS file_name,
SUM(e.bytes)/1024/1024 AS segment_size_mb
FROM dba_extents e
JOIN dba_data_files f ON e.file_id = f.file_id
WHERE f.file_id = 109
GROUP BY e.segment_type, e.segment_name, f.file_name
ORDER BY segment_size_mb DESC;
VAR v_file VARCHAR2(512)
EXEC :v_file := '/u01/app/oracle/oradata/ORCL/users01.dbf'
SELECT e.segment_type, e.segment_name, f.file_name,
SUM(e.bytes)/1024/1024 AS size_mb
FROM dba_extents e
JOIN dba_data_files f ON e.file_id = f.file_id
WHERE f.file_name = :v_file
GROUP BY e.segment_type, e.segment_name, f.file_name
ORDER BY size_mb DESC;
DBA_SEGMENTS 的 HEADER_FILE 僅記錄 段頭所在的文件。一個大表可能跨多個文件,若只看 HEADER_FILE 會漏掉該表在其他文件中的 Extents。DBA_EXTENTS 逐個 Extent 記錄 File ID,精準反映段在各文件的實際分佈。
-- 錯誤:只能看到段頭在該文件的段,漏掉跨文件的段
SELECT ds.segment_name, ds.segment_type, df.file_name, SUM(ds.bytes)/1024/1024
FROM dba_segments ds
JOIN dba_data_files df ON ds.header_file = df.file_id
WHERE df.file_id = 109
GROUP BY ds.segment_name, ds.segment_type, df.file_name;
SELECT f.file_name,
e.segment_type,
COUNT(*) AS extent_count,
SUM(e.bytes)/1024/1024 AS total_mb,
ROUND(RATIO_TO_REPORT(SUM(e.bytes)) OVER (PARTITION BY f.file_id) * 100, 2) AS pct_in_file
FROM dba_extents e
JOIN dba_data_files f ON e.file_id = f.file_id
WHERE f.tablespace_name = 'USERS'
GROUP BY f.file_id, f.file_name, e.segment_type
ORDER BY f.file_id, total_mb DESC;
| 欄位 | 含義 |
|---|---|
| SEGMENT_TYPE | TABLE / INDEX / LOB / LOBINDEX / TABLE PARTITION / INDEX PARTITION 等 |
| SEGMENT_NAME | 段名稱 (表名、索引名、分區名) |
| FILE_NAME | 數據文件完整路徑 |
| SEGMENT_SIZE_MB | 該段在該文件佔用空間 (MB) |
ALTER TABLE ... MOVE 或 SHRINK SPACE。ALTER DATABASE DATAFILE ... RESIZE 或新增文件策略。DROP DATAFILE。查詢數據文件包含的段對象,**務必使用 DBA_EXTENTS 關聯 DBA_DATA_FILES**,而非 DBA_SEGMENTS。掌握此 SQL,可精準掌控表空間內部空間分佈,支撐容量規劃、效能調優、故障排查等核心 DBA 作業。