【问题标题】:How do I calculate tables size in Oracle如何在 Oracle 中计算表大小
【发布时间】:2008-11-05 11:47:31
【问题描述】:

习惯了MSSQL(并且可能被宠坏了),我想知道如何获得Oracle 10g 的表大小。 我用谷歌搜索了它,所以我现在知道我可能没有像sp_spaceused 这样简单的选项。我得到的潜在答案大部分时间仍然过时或不起作用。可能是因为我不是我正在使用的架构的 DBA。

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

【问题讨论】:

  • 如果有一个 proc 给出的答案被破坏了,那么把你从这里得到的答案包装到一个过程中并称之为...... dun dun duh...... sp_spaceused。它真的没有什么魔力。
  • @MarkBrady 也许不是魔法,但需要奥术知识。

标签: oracle


【解决方案1】:

您可能对此查询感兴趣。它告诉您为每个表分配了多少空间,同时考虑到表上的索引和任何 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
;

【讨论】:

  • 请注意,此答案计算段数,它不区分当前使用的空间与先前使用的空间。显然,一旦一个段被分配给一个表,它总是被分配给一个表,即使空间被释放。见here。我想您必须深入到范围级别才能查看实际使用了多少空间
【解决方案2】:
-- 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');

【讨论】:

  • 这些统计数据可能是null(num_rows,avg_row_len),需要先通过下面的语句ANALYZE TABLE your_table COMPUTE STATISTICS做一些分析
  • 严格分析这些可能会很长!
  • 当我无法检查非表空间表时很好解决
  • 我相信这个查询会忽略表中的 blob,您必须使用其他获得 LOB 段的答案
【解决方案3】:

首先,我通常会警告说,为了进行空间分析而收集表统计信息是一件有潜在危险的事情。收集统计信息可能会更改查询计划,特别是如果 DBA 配置了一个使用您的调用未使用的非默认参数的统计信息收集作业,并且会导致 Oracle 重新解析使用相关表的查询,这可能是一种性能打。如果 DBA 故意留下一些没有统计信息的表(如果您的 OPTIMIZER_MODE 是 CHOOSE 则很常见),收集统计信息可能会导致 Oracle 停止使用基于规则的优化器并开始使用基于成本的优化器进行一组查询,这可能是如果在生产中意外完成,则会导致严重的性能问题。如果您的统计准确,您可以直接查询USER_TABLES(或ALL_TABLESDBA_TABLES),无需调用GATHER_TABLE_STATS。如果您的统计数据不准确,可能是有原因的,您不想破坏现状。

其次,与 SQL Server sp_spaceused 过程最接近的等价物可能是 Oracle 的 DBMS_SPACE 包。 Tom Kyte 有一个不错的show_space procedure,它为这个包提供了一个简单的界面,并打印出类似于sp_spaceused 打印出来的信息。

【讨论】:

    【解决方案4】:

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

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

    警告:正如贾斯汀在他的回答中所说,收集优化器统计信息会影响查询优化,不应在没有适当注意和考虑的情况下进行

    然后从生成的stats中找出该表占用的块数:

    select blocks, empty_blocks, num_freelist_blocks
    from   all_tables
    where  owner = 'MYSCHEMA'
    and    table_name = 'MYTABLE';
    
    • 分配给表的总块数为blocks + 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;
    

    注意:阅读this AskTom thread后对上述内容的更改

    【讨论】:

      【解决方案5】:

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

        IIRC 您需要的表是 DBA_TABLES、DBA_EXTENTS 或 DBA_SEGMENTS 和 DBA_DATA_FILES。如果您没有计算机上的管理权限,您可以查看这些表的 USER_ 和 ALL_ 版本。

        【讨论】:

          【解决方案7】:

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

          
          
              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
              ;
          
          

          【讨论】:

            【解决方案8】:
            select segment_name,segment_type,bytes/1024/1024 MB
            from dba_segments
            where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;
            

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                【解决方案10】:

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

                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
                ;
                

                【讨论】:

                  【解决方案11】:

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

                  如果您要估计表的未来增长需要多少空间,那么 avg_row_len 乘以表中的行数(或您期望的表中的行数)将是一个很好的指南。 但是 Oracle 会在每个块上留出一些空闲空间,部分是为了允许行在更新时“增长”,部分是因为在该块上可能无法容纳另一整行(例如,8K 块只能容纳 2 行3K,尽管这将是一个极端的例子,因为 3K 比大多数行大小大得多)。 所以 BLOCKS(在 USER_TABLES 中)可能是一个更好的指南。

                  但是,如果您在一个表中有 200,000 行,删除了其中的一半,那么该表仍将“拥有”相同数量的块。它不会释放它们以供其他表使用。 此外,块不会单独添加到表中,而是以称为“范围”的组的形式添加。因此,表中通常会有 EMPTY_BLOCKS(也在 USER_TABLES 中)。

                  【讨论】:

                    【解决方案12】:

                    更正分区表:

                    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
                    ;
                    

                    【讨论】:

                      【解决方案13】:

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

                      选择表名,(nvl (( 选择总和(块) 从 dba_indexes a,dba_segments b 其中 a.index_name=b.segment_name 和 a.table_name=dba_tables.table_name ),0)+blocks)*8192/1024 TotalSize,blocks*8 tableSize 来自 dba_tables 3 前下单

                      【讨论】:

                        【解决方案14】:

                        我发现这更准确一点:

                        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
                        

                        【讨论】:

                        • 看起来有点像我的回答?
                        【解决方案15】:
                        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 ;
                        

                        【讨论】:

                          【解决方案16】:

                          还有一个选项允许通过连接获得“选择”大小,以及表格大小作为选项

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

                          【讨论】:

                            【解决方案17】:

                            我有与最后一个计算表数据段、表索引和 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;
                            

                            Source.

                            【讨论】:

                              猜你喜欢
                              • 2020-01-17
                              • 2011-12-16
                              • 2022-06-16
                              • 2021-01-02
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多