如何在Oracle中计算表大小


128

习惯于(可能被)MSSQL破坏,我想知道如何在Oracle 10g中获得表大小。我已经用谷歌搜索了,所以我现在知道我可能没有像sp_spaceused那样简单的选项。不过,我得到的潜在答案大部分时间已经过时或无法正常工作。可能是因为我不是正在使用的架构的DBA。

会有人提供解决方案和/或建议吗?


如果有proc给出的答案被宠坏了,则将您从此处获得的答案包装起来,并将其包装到一个过程中并命名为... dun dun duh ... sp_spaceused。真的没有什么魔术。

1
@MarkBrady也许不是魔术,但是需要大量的奥术知识。
jpmc26 2016年

Answers:


201

您可能对此查询感兴趣。它告诉您为每个表分配了多少空间,并考虑了表中的索引和任何LOB。通常,您很想知道“ Purchase Order表占用了多少空间,包括任何索引”,而不仅仅是表本身。您总是可以深入研究细节。请注意,这需要访问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
;

1
请注意,此答案对段进行计数,该段不能区分当前正在使用的空间与以前正在使用的空间。显然,将段分配给表后,即使释放了空间,也总是将其分配给表。看这里。我想您必须深入研究实际使用了多少空间?
jpmc26 2016年

43
-- 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');

2
这些统计信息可能是nullnum_rowsavg_row_len),您需要在通过以下语句进行分析之前ANALYZE TABLE your_table COMPUTE STATISTICS
Brice 2013年

艰难地分析这些可能会很长!
布莱斯2013年

当我无法检查无表空间表时,很好的解决方法
tungns304 '18

30

首先,我通常会警告说,为了进行空间分析而收集表统计信息可能会很危险。收集统计信息可能会更改查询计划,尤其是如果DBA配置了使用您的呼叫未使用的非默认参数的统计信息收集作业,并且会导致Oracle重新解析利用有问题的表的查询,这可能会提高性能。击中。如果DBA故意留下了一些没有统计信息的表(如果您OPTIMIZER_MODE选择CHOOSE,则很常见),收集统计信息可能会导致Oracle停止使用基于规则的优化器,并开始对一组查询使用基于成本的优化器,这可能是一个主要性能。如果在生产中意外完成,则会头痛。如果您的统计信息准确无误,则可以查询USER_TABLESALL_TABLESDBA_TABLES)而不直接致电GATHER_TABLE_STATS。如果您的统计数据不准确,则可能是有原因的,并且您不想打扰现状。

其次,与SQL Server sp_spaceused过程最接近的等效项可能是Oracle的DBMS_SPACE软件包。Tom Kyte有一个很好的show_space过程,可以为该程序包提供简单的界面,并打印出与打印出的内容相似的信息sp_spaceused


8

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

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

警告:就像贾斯汀在回答中所说的那样,收集优化器统计信息会影响查询优化,如果没有适当的注意和考虑,则不应该这样做

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

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

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

将块数乘以使用中的块大小(通常为8KB)即可获得消耗的空间-例如17个块x 8KB = 136KB。

要一次对架构中的所有表执行此操作:

begin
    dbms_stats.gather_schema_stats ('MYSCHEMA');
end;
/

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

注意:阅读此AskTom线程后,对以上内容进行的更改


7

我修改了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
/

6

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



    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
    ;

5

IIRC您需要的表是DBA_TABLES,DBA_EXTENTS或DBA_SEGMENTS和DBA_DATA_FILES。这些表还有USER_和ALL_版本,您可以查看它们是否对计算机没有管理权限。


4

这是WW答案的一个变体,它包括上面其他建议的分区和子分区,以及一列显示类型的列:表/索引/ 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;

3
select segment_name,segment_type,bytes/1024/1024 MB
from dba_segments
where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;

2

我修改了查询以获取每个表空间的架构大小。

SELECT owner,
     tablespace_name,
     TRUNC (SUM (bytes) / 1024 / 1024)   Meg,
     ROUND (ratio_to_report (SUM (bytes)) OVER () * 100) Percent
FROM (SELECT tablespace_name, owner, bytes
        FROM dba_segments
       WHERE segment_type IN
                 ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION')
      UNION ALL
      SELECT i.tablespace_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.tablespace_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.tablespace_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 owner, tablespace_name
--HAVING SUM(bytes)/1024/1024 > 10  /* Ignore really small tables */
ORDER BY tablespace_name -- desc
;

1

取决于“表的大小”的含义。表与文件系统上的特定文件无关。一个表将驻留在一个表空间上(如果已分区,则可能有多个表空间;如果您还想考虑该表上的索引,则可能有多个表空间)。一个表空间中通常会有多个表,并且可能分布在多个文件中。

如果您要估算表的未来增长需要多少空间,那么avg_row_len乘以表中的行数(或表中预期的行数)将是一个很好的指南。但是Oracle将在每个块上保留一些空间,部分是为了让行在更新后能“增长”,部分是因为不可能将另一整行容纳在该块上(例如8K块只能容纳2行) 3K,尽管这将是一个极端的例子,因为3K比大多数行的尺寸大得多)。因此(在USER_TABLES中)BLOCKS可能是更好的指南。

但是,如果表中有20万行,删除了其中的一半,则该表仍将“拥有”相同数量的块。它不会释放它们供其他表使用。此外,块不会单独添加到表中,而是以称为“扩展区”的组添加。因此,表中通常会有EMPTY_BLOCKS(也在USER_TABLES中)。


1

分区表的更正:

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
;

0

简单选择,根据块大小返回表的原始大小,还包括带有索引的大小

选择表名,(nvl((从dba_indexes a,dba_segments b中选择sum(块),其中a.index_name = b.segment_name和a.table_name = dba_tables.table_name),0)+块)* 8192/1024 TotalSize,块* 8 dba_tables中的tableSize按3排序


0

我发现这更加准确:

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

7
看起来有点像我的答案?
WW。

0
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 ;

-2

还有一个选项允许通过联接获得“选择”大小,并且也可以将表大小作为选项

-- 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);

-3

我有和最后一个变量相同的变量,用于计算表数据,表索引和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;

来源

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.