[原]使用Oracle Partition Table对日志表进行分区一例

通过按时间分区并淘汰旧数据,优化日志型表存储与查询效率,减少资源占用,提升系统灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某个系统中有个日志型的表,现在的大小大概超过500MB,与该表相关的语句的执行计划都是对这个表进行全表扫描。

下面是该表的定义:


create table p_siteaccesslog
(
	logID			varchar(40) not null,
	infoType		varchar(20) default 'site',
	siteId			varchar(30),
	columnId		varchar(30),
	infoId			varchar(30),
	url				varchar(300),
	location		varchar(80),
	action			varchar(20),
	accessDate		varchar(10),     
	accessTime		varchar(8),
	sessionID		varchar(90),
	userName		varchar(30),
	userBrowser		varchar(50),
	userOS			varchar(30),
	userIp			varchar(30),
	localization	varchar(100),
	constraint PK_p_siteaccesslog primary key (logID) 
)

该表有一个主键,为每条日志分配一个主键,感觉上一百年都不会用上这个主键来查一次数据。所以在新的分区表上将其去掉。


test$ora8i@4.20 SQL> l
  1* select segment_name,sum(bytes/1048576) MB from user_extents group by segment_name order by 2 desc
test$ora8i@4.20 SQL> /

SEGMENT_NAME                                     MB
---------------------------------------- ----------
P_SITEACCESSLOG                                 536

由于是日志型的表,第一感觉就是按照时间分区,并淘汰(切换)旧的数据。

于是沿着这个思路,按照每月一个分区的策略构建分区表:


create table my_p_siteaccesslog
(
	logID			varchar(40) not null,
	infoType		varchar(20) default 'site',
	siteId			varchar(30),
	columnId		varchar(30),
	infoId			varchar(30),
	url				varchar(300),
	location		varchar(80),
	action			varchar(20),
	accessDate		varchar(10), 
	accessTime		varchar(8),
	sessionID		varchar(90),
	userName		varchar(30),
	userBrowser		varchar(50),
	userOS			varchar(30),
	userIp			varchar(30),
	localization	varchar(100)
)
partition by range (accessDate) 
(
	partition pbf2009 values less than ('2009-01-01'),
	partition p200901 values less than ('2009-02-01'),
	partition p200902 values less than ('2009-03-01'),
	partition p200903 values less than ('2009-04-01'),
	partition p200904 values less than ('2009-05-01'),
	partition p200905 values less than ('2009-06-01'),
	partition p200906 values less than ('2009-07-01'),
	partition p200907 values less than ('2009-08-01'),
	partition p200908 values less than ('2009-09-01'),
	partition p200909 values less than ('2009-10-01'),
	partition p200910 values less than ('2009-11-01'),
	partition p200911 values less than ('2009-12-01'),
	partition p200912 values less than ('2010-01-01'),
	partition p201001 values less than ('2010-02-01'),
	partition p201002 values less than ('2010-03-01'),
	partition p201003 values less than ('2010-04-01'),
	partition p201004 values less than ('2010-05-01'),
	partition p201005 values less than ('2010-06-01'),
	partition p201006 values less than ('2010-07-01'),
	partition p201007 values less than ('2010-08-01'),
	partition p201008 values less than ('2010-09-01'),
	partition p201009 values less than ('2010-10-01'),
	partition p201010 values less than ('2010-11-01'),
	partition p201011 values less than ('2010-12-01'),
	partition p201012 values less than ('2011-01-01')
)

由于数据库是Oracle 10g,不是11g,无法支持interval分区,只能多创建几个未来的分区了。

表创建好之后,就导数据流,由于该表不算太大,500多兆的插入还是可以接受的。


insert into my_p_siteaccesslog select * from P_SITEACCESSLOG ; 
commit;

下一步使用分区切换技术,将旧的数据搬走(不是删掉)

创建用于存放2008年数据大表


create table my_p_siteaccesslog_2008
(
	logID			varchar(40) not null,
	infoType		varchar(20) default 'site',
	siteId			varchar(30),
	columnId		varchar(30),
	infoId			varchar(30),
	url				varchar(300),
	location		varchar(80),
	action			varchar(20),
	accessDate		varchar(10), 
	accessTime		varchar(8),
	sessionID		varchar(90),
	userName		varchar(30),
	userBrowser		varchar(50),
	userOS			varchar(30),
	userIp			varchar(30),
	localization	varchar(100)
);

使用分区切换,将2008年的数据切换出来:


ALTER TABLE my_p_siteaccesslog EXCHANGE PARTITION pbf2009 WITH TABLE my_p_siteaccesslog_2008;

创建专门用于存放2009年数据的分区表:


create table my_p_siteaccesslog_2009
(
	logID			varchar(40) not null,
	infoType		varchar(20) default 'site',
	siteId			varchar(30),
	columnId		varchar(30),
	infoId			varchar(30),
	url				varchar(300),
	location		varchar(80),
	action			varchar(20),
	accessDate		varchar(10), 
	accessTime		varchar(8),
	sessionID		varchar(90),
	userName		varchar(30),
	userBrowser		varchar(50),
	userOS			varchar(30),
	userIp			varchar(30),
	localization	varchar(100)
)
partition by range (accessdate)
(
	partition p200901 values less than ('2009-02-01'),
	partition p200902 values less than ('2009-03-01'),
	partition p200903 values less than ('2009-04-01'),
	partition p200904 values less than ('2009-05-01'),
	partition p200905 values less than ('2009-06-01'),
	partition p200906 values less than ('2009-07-01'),
	partition p200907 values less than ('2009-08-01'),
	partition p200908 values less than ('2009-09-01'),
	partition p200909 values less than ('2009-10-01'),
	partition p200910 values less than ('2009-11-01'),
	partition p200911 values less than ('2009-12-01'),
	partition p200912 values less than ('2010-01-01')
)

令人非常郁闷的是Oracle竟然不支持两个分区表之间的分区切换,一定要借助一个中间表,这个功能连SQL Server都有了啊。

于是创建一个专门用于切换的中间表:


create table my_p_siteaccesslog_exchange
(
	logID			varchar(40) not null,
	infoType		varchar(20) default 'site',
	siteId			varchar(30),
	columnId		varchar(30),
	infoId			varchar(30),
	url				varchar(300),
	location		varchar(80),
	action			varchar(20),
	accessDate		varchar(10), 
	accessTime		varchar(8),
	sessionID		varchar(90),
	userName		varchar(30),
	userBrowser		varchar(50),
	userOS			varchar(30),
	userIp			varchar(30),
	localization	varchar(100)
);

下面就是毫无技术含量并且不断重复的就借助中间表将my_p_siteaccesslog中的2009年数据切换到中my_p_siteaccesslog_2009中的代码:


ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200901 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200901 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200902 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200902 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200903 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200903 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200904 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200904 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200905 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200905 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200906 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200906 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200907 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200907 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200908 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200908 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200909 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200909 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200910 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200910 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200911 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200911 WITH TABLE my_p_siteaccesslog_exchange;

ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p200912 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2009 EXCHANGE PARTITION p200912 WITH TABLE my_p_siteaccesslog_exchange;

顺便创建存放2010年数据的分区表


create table my_p_siteaccesslog_2010
(
	logID			varchar(40) not null,
	infoType		varchar(20) default 'site',
	siteId			varchar(30),
	columnId		varchar(30),
	infoId			varchar(30),
	url				varchar(300),
	location		varchar(80),
	action			varchar(20),
	accessDate		varchar(10), 
	accessTime		varchar(8),
	sessionID		varchar(90),
	userName		varchar(30),
	userBrowser		varchar(50),
	userOS			varchar(30),
	userIp			varchar(30),
	localization	varchar(100)
)
partition by range (accessdate)
(
	partition p201001 values less than ('2010-02-01'),
	partition p201002 values less than ('2010-03-01'),
	partition p201003 values less than ('2010-04-01'),
	partition p201004 values less than ('2010-05-01'),
	partition p201005 values less than ('2010-06-01'),
	partition p201006 values less than ('2010-07-01'),
	partition p201007 values less than ('2010-08-01'),
	partition p201008 values less than ('2010-09-01'),
	partition p201009 values less than ('2010-10-01'),
	partition p201010 values less than ('2010-11-01'),
	partition p201011 values less than ('2010-12-01'),
	partition p201012 values less than ('2011-01-01')
)

并将1月份的数据切换到表my_p_siteaccesslog_2010中:


ALTER TABLE my_p_siteaccesslog      EXCHANGE PARTITION p201001 WITH TABLE my_p_siteaccesslog_exchange;
ALTER TABLE my_p_siteaccesslog_2010 EXCHANGE PARTITION p201001 WITH TABLE my_p_siteaccesslog_exchange;

经过一轮折腾之后,我们看看现各个表的情况:


test$ora8i@4.20 SQL> l
  1* select segment_name,sum(bytes/1048576) MB from user_extents group by segment_name order by 2 desc
test$ora8i@4.20 SQL> /

SEGMENT_NAME                                     MB
---------------------------------------- ----------
P_SITEACCESSLOG                                 536
MY_P_SITEACCESSLOG_2009                         435
MY_P_SITEACCESSLOG_2008                          51
MY_P_SITEACCESSLOG_2010                     45.6875
MY_P_SITEACCESSLOG                          35.1875
MY_P_SITEACCESSLOG_EXCHANGE                   .0625

表MY_P_SITEACCESSLOG以后将会改名为P_SITEACCESSLOG正式上线使用,其中仅保留1~2个月的数据用于查询,当需要查询旧数据的时候,应用可以不动,然后将旧的数据切换到MY_P_SITEACCESSLOG(也就是以后的P_SITEACCESSLOG)中就可以使用了。

分区表的切换产生的redo非常少,主要都是用于数据字典,因此系统的灵活性变得更高了。

<think>首先,用户的问题是:“请问Oracle 查看大小 包括分区和包含LOB字段的”。从系统级指令看,我需要使用中文回答,确保LaTeX语法正确,行内数学达式用$...$,独立公式用$$...$$,并生成相关问题。 用户意图是了解如何在Oracle数据库中查看大小,特别是针对普通分区和包含LOB字段的。引用提供了相关信息,但主要是关于LOB字段的存储和移动空间的,我需要基于这些引用和一般知识来回答。 关键引用: - 引用[1]:提到LOB字段会创建两个单独的segment(数据段和索引段),存储在对应空间中。 - 引用[2]:给出了一个SQL语句模板来移动LOB字段的空间。 - 引用[3]:展示了LOB存储的语法。 - 引用[4]:提供了查看分区大小的SQL片段,包括对LOB的处理。 用户上次的问题可能涉及大小,所以我需要整合这些信息来回答如何查看大小。 结构化回答: 1. **理解大小在Oracle中的组成**:在Oracle中,大小由多个segment组成,包括段、LOB段(如果包含LOB字段)、索引段等。对于分区,每个分区可能有自己的segment。 2. **查看大小的通用方法**: - 使用数据字典视图如`DBA_SEGMENTS`、`USER_SEGMENTS`或`ALL_SEGMENTS`。 - 示例查询:`SELECT SEGMENT_NAME, BYTES/1024/1024 AS SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_TYPE = 'TABLE' AND SEGMENT_NAME = '名';` 3. **处理LOB字段**:如果包含LOB字段,LOB数据存储在单独的LOB段中,需要额外查询这些段的大小。 - 引用[1]提到LOB字段有两个segment:一个用于LOB数据,另一个用于LOB索引。 - 引用[4]提供了一个SQL片段:`TRUNC(SUM(DECODE(A.SEGMENT_TYPE,'TABLE',A.BYTES,'TABLE PARTITION',A.BYTES,0)) / 1024 / 1024) TABLE_MB`,这可以用于聚合大小。 4. **处理分区**:分区可能有多个分区,每个分区有自己的segment。 - 在查询中考虑`SEGMENT_TYPE`如`TABLE PARTITION`。 - 引用[4]的查询已经处理了分区。 5. **综合查询**:构建一个查询来获取的总大小,包括LOB段和分区。 - 基于引用[4],我可以扩展它。 - 例如:查询所有segment类型的大小和。 完整查询建议: - 对于单个,包括LOB和分区: ```sql SELECT SEGMENT_NAME, SEGMENT_TYPE, BYTES/1024/1024 AS SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_NAME IN ( SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = '名' UNION ALL SELECT SEGMENT_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' UNION ALL SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = '名' ); ``` - 更精确的:使用`DBA_EXTENTS`或直接聚合。 引用[4]的查询更全面: `TRUNC(SUM(DECODE(A.SEGMENT_TYPE,'TABLE',A.BYTES,'TABLE PARTITION',A.BYTES,0)) / 1024 / 1024) TABLE_MB` – 这似乎只处理分区,不包括LOB。我需要包括LOB段。 修改引用[4]的查询: - 添加LOB段类型:LOB段类型是`LOBSEGMENT`和`LOBINDEX`(根据知识)。 - 在Oracle中,LOB段类型是`LOBSEGMENT`和`LOBINDEX`。 最终查询: ```sql SELECT TABLE_NAME, TRUNC(SUM( CASE WHEN SEGMENT_TYPE IN ('TABLE', 'TABLE PARTITION', 'LOBSEGMENT', 'LOBINDEX') THEN BYTES ELSE 0 END ) / 1024 / 1024) AS TOTAL_SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_NAME IN ( SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = '名' UNION ALL SELECT SEGMENT_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' -- 获取LOB段名 UNION ALL SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = '名' -- 获取分区名 ) GROUP BY TABLE_NAME; ``` 但这可能不完美,因为LOB段名可能不直接匹配名。更好的方式是使用`DBA_LOBS`视图来获取LOB段名。 标准方法: - 查询`DBA_SEGMENTS`,连接相关视图。 - 例如: ```sql SELECT t.TABLE_NAME, SUM(s.BYTES) / 1024 / 1024 AS TOTAL_SIZE_MB FROM USER_TABLES t JOIN USER_SEGMENTS s ON s.SEGMENT_NAME = t.TABLE_NAME AND s.SEGMENT_TYPE IN ('TABLE', 'TABLE PARTITION') LEFT JOIN USER_LOBS l ON l.TABLE_NAME = t.TABLE_NAME LEFT JOIN USER_SEGMENTS ls ON ls.SEGMENT_NAME = l.SEGMENT_NAME -- 假设SEGMENT_NAME在USER_LOBS中 GROUP BY t.TABLE_NAME; ``` 在`USER_LOBS`中,有`SEGMENT_NAME`列示LOB段名。 基于引用[2]:`SELECT 'alter table '||a.owner||'.'||a.table_name||' move lob('||a.COLUMN_NAME||') store as (tablespace DATALOB);'` – 这明可以从`USER_LOBS`获取信息。 所以,完整查询: ```sql SELECT t.TABLE_NAME, TRUNC(SUM( CASE WHEN s.SEGMENT_TYPE IN ('TABLE', 'TABLE PARTITION') THEN s.BYTES WHEN s.SEGMENT_TYPE = 'LOBSEGMENT' THEN s.BYTES WHEN s.SEGMENT_TYPE = 'LOBINDEX' THEN s.BYTES ELSE 0 END ) / 1024 / 1024) AS TOTAL_SIZE_MB FROM USER_TABLES t LEFT JOIN USER_SEGMENTS s ON s.SEGMENT_NAME = t.TABLE_NAME AND s.SEGMENT_TYPE IN ('TABLE', 'TABLE PARTITION') LEFT JOIN USER_LOBS l ON l.TABLE_NAME = t.TABLE_NAME LEFT JOIN USER_SEGMENTS ls ON ls.SEGMENT_NAME = l.SEGMENT_NAME AND ls.SEGMENT_TYPE IN ('LOBSEGMENT', 'LOBINDEX') WHERE t.TABLE_NAME = '名' -- 指定名 GROUP BY t.TABLE_NAME; ``` 但这可能重复或不准确。更简单的方式是查询所有segment关联到。 最佳实践: - 使用`DBA_EXTENTS`或直接查询`DBA_SEGMENTS`,过滤SEGMENT_NAME基于名。 - 对于LOB,LOB段名通常与名相关,但最好通过`DBA_LOBS`。 一个可靠查询: ```sql SELECT TABLE_NAME, TRUNC(SUM(BYTES) / 1024 / 1024) AS TOTAL_SIZE_MB FROM ( SELECT TABLE_NAME, SEGMENT_NAME, SEGMENT_TYPE FROM USER_TABLES UNION ALL SELECT TABLE_NAME, SEGMENT_NAME, 'LOBSEGMENT' FROM USER_LOBS UNION ALL SELECT TABLE_NAME, INDEX_NAME AS SEGMENT_NAME, 'LOBINDEX' FROM USER_LOBS -- 可能需要调整 ) segs JOIN USER_SEGMENTS s ON s.SEGMENT_NAME = segs.SEGMENT_NAME WHERE TABLE_NAME = '名' GROUP BY TABLE_NAME; ``` 这需要调整,因为LOB索引可能有单独的段。 在Oracle中,LOB索引通常与LOB段一起管理,但查询`USER_LOBS`提供LOB段名,LOB索引段名可能不同。 简化:查询`USER_SEGMENTS`,并过滤SEGMENT_TYPE包括'TABLE', 'TABLE PARTITION', 'LOBSEGMENT', 'LOBINDEX',然后通过名关联。 但SEGMENT_NAME可能不直接是名。对于分区分区名是SEGMENT_NAME。 所以,对于指定,需要获取所有相关segment名。 最终查询建议: ```sql SELECT '名' AS TABLE_NAME, TRUNC(SUM(BYTES) / 1024 / 1024) AS TOTAL_SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_NAME IN ( SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = '名' -- 段 UNION ALL SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = '名' -- 分区段 UNION ALL SELECT SEGMENT_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' -- LOB段 UNION ALL SELECT INDEX_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' -- LOB索引段?但USER_LOBS中没有直接INDEX_NAME ); ``` 在`USER_LOBS`中,有`INDEX_NAME`列示LOB索引名。 引用Oracle文档:`USER_LOBS`视图有`SEGMENT_NAME` for LOB segment and `INDEX_NAME` for LOB index. 所以: ```sql SELECT '名' AS TABLE_NAME, TRUNC(SUM(BYTES) / 1024 / 1024) AS TOTAL_SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_NAME IN ( SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = '名' UNION ALL SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = '名' UNION ALL SELECT SEGMENT_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' UNION ALL SELECT INDEX_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' ); ``` 这应该工作。 现在,回答结构: 1. **解释大小的组成**:在Oracle中,的大小包括数据段、索引段(包括LOB索引)、LOB数据段等。对于分区,每个分区有自己的段。 2. **通用查看方法**:使用`USER_SEGMENTS`视图。 3. **具体步骤**: - 对于普通:简单查询`USER_SEGMENTS`。 - 对于包含LOB字段的:需要包括LOB段。 - 对于分区:需要包括所有分区段。 4. **提供SQL查询**:给出一个综合查询。 5. **注意事项**:需要适当权限;大小是近似值;等。 生成相关问题: - 基于主题:如何优化大小?如何移动LOB段?等。 最终回答框架: - 开头:解释Oracle大小的概念。 - 步骤:逐步如何查看大小。 - SQL示例。 - 结尾:相关问题。</think>### Oracle 查看大小(包括分区和包含LOB字段的) 在Oracle数据库中,的大小由多个段(segment)组成,包括数据段、LOB数据段、LOB索引段等。对于分区,每个分区可能有独立的段。LOB(Large Object)字段(如BLOB、CLOB)会创建额外的LOB段和LOB索引段,这些段需要单独统计。以下是查看大小的详细方法,基于Oracle数据字典视图(如`DBA_SEGMENTS`、`USER_LOBS`等)。 #### 1. **理解大小的组成** - **普通**:大小主要来自段(`SEGMENT_TYPE = 'TABLE'`)。 - **分区**:大小来自所有分区段(`SEGMENT_TYPE = 'TABLE PARTITION'`),每个分区是一个独立段。 - **包含LOB字段的**: - LOB数据段(`SEGMENT_TYPE = 'LOBSEGMENT'`):存储LOB字段的实际数据。 - LOB索引段(`SEGMENT_TYPE = 'LOBINDEX'`):管理LOB数据的索引。 - 建立时,Oracle会自动为LOB字段创建这两个段,存储在指定的空间中[^1]。 - 总大小 = 段大小 + 所有分区段大小 + LOB数据段大小 + LOB索引段大小。 #### 2. **查看大小的通用方法** 使用数据字典视图`DBA_SEGMENTS`(需要DBA权限)或`USER_SEGMENTS`(当前用户权限)。以下查询以`USER_SEGMENTS`为例,单位为MB: ```sql -- 查看单个段的大小 SELECT SEGMENT_NAME, SEGMENT_TYPE, BYTES/1024/1024 AS SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_NAME = '段名'; ``` #### 3. **综合查询:包括分区和LOB字段** 以下查询计算指定的总大小(包括分区和LOB段),替换`'名'`为实际名: ```sql SELECT '名' AS TABLE_NAME, TRUNC(SUM(BYTES) / 1024 / 1024) AS TOTAL_SIZE_MB FROM USER_SEGMENTS WHERE SEGMENT_NAME IN ( -- 段或分区段 SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = '名' UNION ALL SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = '名' -- LOB段(数据和索引) UNION ALL SELECT SEGMENT_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' -- LOB数据段 UNION ALL SELECT INDEX_NAME FROM USER_LOBS WHERE TABLE_NAME = '名' -- LOB索引段 ); ``` **说明**: - 结果`TOTAL_SIZE_MB`是的总大小(MB)。 - **分区处理**:通过`USER_TAB_PARTITIONS`获取所有分区名,确保分区段被包括[^4]。 - **LOB字段处理**:通过`USER_LOBS`获取LOB段名和索引名,确保LOB数据段和索引段被包括[^1][^2]。 - 如果分区或LOB字段,查询会自动忽略无关部分。 - **权限要求**:使用`DBA_SEGMENTS`替代`USER_SEGMENTS`可查看所有(需`SELECT ANY DICTIONARY`权限)。 #### 4. **示例输出** 假设`EMPLOYEES`包含LOB字段(如`RESUME CLOB`)且已分区: ```sql -- 查询:SELECT ... WHERE TABLE_NAME = 'EMPLOYEES' ``` 输出可能: ``` TABLE_NAME | TOTAL_SIZE_MB ------------|-------------- EMPLOYEES | 350 ``` 这总大小为350MB,包括段、分区段、LOB数据段和LOB索引段。 #### 5. **注意事项** - **大小准确性**:`BYTES`是段分配的物理空间,可能高于实际数据大小(因区段扩展或空闲空间)。使用`DBMS_SPACE`包可获取更精确分析。 - **LOB存储细节**:LOB段可通过`ENABLE STORAGE IN ROW`等参数优化存储[^3],但这不影响大小查询。 - **性能影响**:在大型系统中,直接查询`DBA_SEGMENTS`可能较慢,建议在非高峰时段运行。 - **移动LOB段**:如果需要迁移LOB段空间,需使用`ALTER TABLE ... MOVE LOB(...) STORE AS ...`语法[^2],而非标准`MOVE TABLESPACE`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值