如何在Oracle中计算表的大小

习惯于(并可能被MSSQL损坏),我想知道如何在Oracle 10g中获得表大小。 我已经search了,所以我现在知道,我可能没有像sp_spaceused一样简单的选项。 我所得到的潜在答案大部分时间都是过时或不起作用。 可能是因为我正在使用的模式上没有DBA。

谁会有解决scheme和build议?

您可能对此查询感兴趣。 它会告诉您为每个表分配多less空间,同时考虑表中的索引和任何LOB。 通常,您有兴趣知道“采购订单表格需要多less空间,包括任何索引”,而不仅仅是表格本身。 你总是可以深入细节。 请注意,这需要访问DBA_ *视图。

COLUMN TABLE_NAME FORMAT A32 COLUMN OBJECT_NAME FORMAT A32 COLUMN OWNER FORMAT A10 SELECT owner, table_name, TRUNC(sum(bytes)/1024/1024) Meg, ROUND( ratio_to_report( sum(bytes) ) over () * 100) Percent FROM (SELECT segment_name table_name, owner, bytes FROM dba_segments WHERE segment_type IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION') UNION ALL SELECT i.table_name, i.owner, s.bytes FROM dba_indexes i, dba_segments s WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type IN ('INDEX', 'INDEX PARTITION', 'INDEX SUBPARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.segment_name AND s.owner = l.owner AND s.segment_type IN ('LOBSEGMENT', 'LOB PARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.index_name AND s.owner = l.owner AND s.segment_type = 'LOBINDEX') WHERE owner in UPPER('&owner') GROUP BY table_name, owner HAVING SUM(bytes)/1024/1024 > 10 /* Ignore really small tables */ ORDER BY SUM(bytes) desc ; 
 -- Tables + Size MB select owner, table_name, round((num_rows*avg_row_len)/(1024*1024)) MB from all_tables where owner not like 'SYS%' -- Exclude system tables. and num_rows > 0 -- Ignore empty Tables. order by MB desc -- Biggest first. ; --Tables + Rows select owner, table_name, num_rows from all_tables where owner not like 'SYS%' -- Exclude system tables. and num_rows > 0 -- Ignore empty Tables. order by num_rows desc -- Biggest first. ; 

注意:这些是估计值,通过收集统计数据更准确:

 exec dbms_utility.analyze_schema(user,'COMPUTE'); 

首先,我通常会警告说,收集表格统计数据以进行空间分析是一个潜在的危险的事情。 收集统计信息可能会改变查询计划,特别是如果DBAconfiguration了一个使用您的调用未使用的非默认参数的统计信息收集作业,并且会导致Oracle重新parsing使用相关表的查询,这可能是一个性能击中。 如果DBA有意留下了一些没有统计信息的表(如果OPTIMIZER_MODE是CHOOSE,那么通用),收集统计信息会导致Oracle停止使用基于规则的优化器,并开始使用基于成本的优化器来处理一组可能成为主要如果在生产中出乎意料地完成了性能上的头痛。 如果您的统计信息准确无误,则可以直接查询USER_TABLES (或ALL_TABLESDBA_TABLES ),而无需调用GATHER_TABLE_STATS 。 如果你的统计数据不准确,可能有一个原因,你不想打扰现状。

其次,与SQL Server sp_spaceused过程最接近的是Oracle的DBMS_SPACE包。 Tom Kyte有一个很好的show_space过程 ,它为这个包提供一个简单的接口,并输出类似于sp_spaceused输出的信息。

首先,在桌面上收集优化器统计信息(如果还没有的话):

 begin dbms_stats.gather_table_stats('MYSCHEMA','MYTABLE'); end; / 

警告:Justin在答复中说,收集优化器统计信息会影响查询优化,不应该在没有适当注意和考虑的情况下完成

然后从生成的统计信息中查找表占用的块数:

 select blocks, empty_blocks, num_freelist_blocks from all_tables where owner = 'MYSCHEMA' and table_name = 'MYTABLE'; 
  • 分配给表的块总数是blocks + empty_blocks + num_freelist_blocks。

  • 块是实际包含数据的块的数量。

将块数乘以正在使用的块大小(通常为8KB)以获得消耗的空间 – 例如17块×8KB = 136KB。

要一次对模式中的所有表执行此操作:

 begin dbms_stats.gather_schema_stats ('MYSCHEMA'); end; / select table_name, blocks, empty_blocks, num_freelist_blocks from user_tables; 

注意:读取此AskTom线程后,对上述内容进行了更改

IIRC你需要的表是DBA_TABLES,DBA_EXTENTS或者DBA_SEGMENTS和DBA_DATA_FILES。 如果您在计算机上没有pipe理权限,也可以看到这些表的USER_和ALL_版本。

对于子分区表和索引,我们可以使用下面的查询

 SELECT owner, table_name, ROUND(sum(bytes)/1024/1024/1024, 2) GB FROM (SELECT segment_name table_name, owner, bytes FROM dba_segments WHERE segment_type IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION') UNION ALL SELECT i.table_name, i.owner, s.bytes FROM dba_indexes i, dba_segments s WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type IN ('INDEX', 'INDEX PARTITION', 'INDEX SUBPARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.segment_name AND s.owner = l.owner AND s.segment_type = 'LOBSEGMENT' UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.index_name AND s.owner = l.owner AND s.segment_type = 'LOBINDEX') WHERE owner in UPPER('&owner') GROUP BY table_name, owner HAVING SUM(bytes)/1024/1024 > 10 /* Ignore really small tables */ ORDER BY SUM(bytes) DESC ; 

我修改了WW的查询来提供更详细的信息:

 SELECT * FROM ( SELECT owner, object_name, object_type, table_name, ROUND(bytes)/1024/1024 AS meg, tablespace_name, extents, initial_extent, ROUND(Sum(bytes/1024/1024) OVER (PARTITION BY table_name)) AS total_table_meg FROM ( -- Tables SELECT owner, segment_name AS object_name, 'TABLE' AS object_type, segment_name AS table_name, bytes, tablespace_name, extents, initial_extent FROM dba_segments WHERE segment_type IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION') UNION ALL -- Indexes SELECT i.owner, i.index_name AS object_name, 'INDEX' AS object_type, i.table_name, s.bytes, s.tablespace_name, s.extents, s.initial_extent FROM dba_indexes i, dba_segments s WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type IN ('INDEX', 'INDEX PARTITION', 'INDEX SUBPARTITION') -- LOB Segments UNION ALL SELECT l.owner, l.column_name AS object_name, 'LOB_COLUMN' AS object_type, l.table_name, s.bytes, s.tablespace_name, s.extents, s.initial_extent FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.segment_name AND s.owner = l.owner AND s.segment_type = 'LOBSEGMENT' -- LOB Indexes UNION ALL SELECT l.owner, l.column_name AS object_name, 'LOB_INDEX' AS object_type, l.table_name, s.bytes, s.tablespace_name, s.extents, s.initial_extent FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.index_name AND s.owner = l.owner AND s.segment_type = 'LOBINDEX' ) WHERE owner = UPPER('&owner') ) WHERE total_table_meg > 10 ORDER BY total_table_meg DESC, meg DESC / 

下面是WW的一个变种,它包括上面提到的其他分区和子分区,还有一个显示TYPE:Table / Index / LOB等的列

 SELECT owner, "Type", table_name "Name", TRUNC(sum(bytes)/1024/1024) Meg FROM ( SELECT segment_name table_name, owner, bytes, 'Table' as "Type" FROM dba_segments WHERE segment_type in ('TABLE','TABLE PARTITION','TABLE SUBPARTITION') UNION ALL SELECT i.table_name, i.owner, s.bytes, 'Index' as "Type" FROM dba_indexes i, dba_segments s WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type in ('INDEX','INDEX PARTITION','INDEX SUBPARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes, 'LOB' as "Type" FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.segment_name AND s.owner = l.owner AND s.segment_type IN ('LOBSEGMENT','LOB PARTITION','LOB SUBPARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes, 'LOB Index' as "Type" FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.index_name AND s.owner = l.owner AND s.segment_type = 'LOBINDEX') WHERE owner in UPPER('&owner') GROUP BY table_name, owner, "Type" HAVING SUM(bytes)/1024/1024 > 10 /* Ignore really small tables */ ORDER BY SUM(bytes) desc; 
 select segment_name,segment_type,bytes/1024/1024 MB from dba_segments where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc; 

取决于“桌子的大小”。 表格不涉及文件系统上的特定文件。 一个表将驻留在一个表空间上(如果它是分区的话可能会有多个表空间,如果你还想考虑表上的索引,可能会有多个表空间)。 一个表空间通常会包含多个表格,并可能分散在多个文件中。

如果您估算了表的未来增长需要多less空间,那么avg_row_len乘以表中的行数(或表中所期望的行数)将是一个很好的指导。 但是,Oracle会在每个块上留出一些空闲的空间,部分是为了允许行更新,如果它们被更新的话,部分原因是它可能无法在该块上安装另一整行(例如,一个8K块只适合2行的3K,尽pipe这将是一个极端的例子,因为3K比大多数行大小大很多)。 所以BLOCKS(在USER_TABLES中)可能是一个更好的指导。

但是如果你在一张表中有20万行,删除了其中的一半,那么这个表仍然会拥有相同数量的块。 它不会释放它们以供其他表使用。 此外,块不会单独添加到表中,而是以称为“范围”的组来添加。 所以在表中通常会有EMPTY_BLOCKS(也在USER_TABLES中)。

更正分区表:

 SELECT owner, table_name, ROUND(sum(bytes)/1024/1024/1024, 2) GB FROM (SELECT segment_name table_name, owner, bytes FROM dba_segments WHERE segment_type IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION') UNION ALL SELECT i.table_name, i.owner, s.bytes FROM dba_indexes i, dba_segments s WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type IN ('INDEX', 'INDEX PARTITION', 'INDEX SUBPARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.segment_name and s.owner = l.owner AND s.segment_type in ('LOBSEGMENT', 'LOB PARTITION', 'LOB SUBPARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.index_name AND s.owner = l.owner AND s.segment_type = 'LOBINDEX') WHERE owner in UPPER('&owner') GROUP BY table_name, owner HAVING SUM(bytes)/1024/1024 > 10 /* Ignore really small tables */ order by sum(bytes) desc ; 

根据块大小返回表的原始大小的简单select也包括带索引的大小

selecttable_name,(nvl((从dba_indexes aselectsum(blocks),dba_segments b其中a.index_name = b.segment_name和a.table_name = dba_tables.table_name),0)+ blocks)* 8192/1024 TotalSize,blocks * 8 dba_tables中的tableSize由3sorting

我发现这样会更准确些:

 SELECT owner, table_name, TRUNC(sum(bytes)/1024/1024/1024) GB FROM (SELECT segment_name table_name, owner, bytes FROM dba_segments WHERE segment_type in ('TABLE','TABLE PARTITION') UNION ALL SELECT i.table_name, i.owner, s.bytes FROM dba_indexes i, dba_segments s WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type in ('INDEX','INDEX PARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.segment_name AND s.owner = l.owner AND s.segment_type IN ('LOBSEGMENT','LOB PARTITION') UNION ALL SELECT l.table_name, l.owner, s.bytes FROM dba_lobs l, dba_segments s WHERE s.segment_name = l.index_name AND s.owner = l.owner AND s.segment_type = 'LOBINDEX') ---WHERE owner in UPPER('&owner') GROUP BY table_name, owner HAVING SUM(bytes)/1024/1024 > 10 /* Ignore really small tables */ ORDER BY SUM(bytes) desc 
 select segment_name as tablename, sum(bytes/ (1024 * 1024 * 1024)) as tablesize_in_GB From dba_segments /* if looking at tables not owned by you else use user_segments */ where segment_name = 'TABLE_WHOSE_SIZE_I_WANT_TO_KNOW' and OWNER = 'WHO OWNS THAT TABLE' /* if user_segments is used delete this line */ group by segment_name ; 

还有一个选项允许用连接来获得“select”大小,而表格大小也是可选的

 -- 1 EXPLAIN PLAN FOR SELECT Scheme.Table_name.table_column1 AS "column1", Scheme.Table_name.table_column2 AS "column2", Scheme.Table_name.table_column3 AS "column3", FROM Scheme.Table_name WHERE ; SELECT * FROM TABLE (DBMS_XPLAN.display); 

我有与最后一个计算表数据,表索引和blob字段段相同的变种:

 CREATE OR REPLACE FUNCTION SYS.RAZMER_TABLICY_RAW(pNazvanie in varchar, pOwner in varchar2) return number is val number(16); sz number(16); begin sz := 0; --Calculate size of table data segments select sum(t.bytes) into val from sys.dba_segments t where t.segment_name = upper(pNazvanie) and t.owner = upper(pOwner); sz := sz + nvl(val,0); --Calculate size of table indexes segments select sum(s.bytes) into val from all_indexes t inner join dba_segments s on t.index_name = s.segment_name where t.table_name = upper(pNazvanie) and t.owner = upper(pOwner); sz := sz + nvl(val,0); --Calculate size of table blob segments select sum(s.bytes) into val from all_lobs t inner join dba_segments s on t.segment_name = s.segment_name where t.table_name = upper(pNazvanie) and t.owner = upper(pOwner); sz := sz + nvl(val,0); return sz; end razmer_tablicy_raw; 

来源 。