Como calculo o tamanho das tabelas no Oracle


128

Sendo acostumado (e potencialmente estragado) pelo MSSQL, estou pensando em como posso obter o tamanho das tabelas no Oracle 10g. Eu pesquisei no Google e agora estou ciente de que talvez não tenha uma opção tão fácil quanto sp_spaceused. Ainda assim, as respostas em potencial que recebi estão desatualizadas na maioria das vezes ou não funcionam. Provavelmente porque não sou DBA no esquema com o qual estou trabalhando.

Alguém teria soluções e / ou recomendações?


se ter um proc dando a resposta está sendo estragado, pegue as respostas que você obteve daqui e envolva-as em um procedimento e chame-o ... dun dun duh ... sp_spaceused. Há realmente pouca mágica nisso.

1
@ MarkBrady Talvez não seja mágico, mas é necessária uma tonelada de conhecimento arcano.
jpmc26

Respostas:


201

Você pode estar interessado nesta consulta. Ele informa quanto espaço é alocado para cada tabela, levando em consideração os índices e quaisquer LOBs na tabela. Muitas vezes, você está interessado em saber "quanto espaço a tabela de pedidos ocupa, incluindo quaisquer índices", em vez de apenas a própria tabela. Você sempre pode se aprofundar nos detalhes. Observe que isso requer acesso às visualizações 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
Observe que esta resposta conta segmentos, que não fazem distinção entre o espaço atualmente em uso e o espaço anteriormente em uso. Aparentemente, uma vez que um segmento é atribuído a uma tabela, ele sempre é atribuído a uma tabela, mesmo que o espaço seja liberado. Veja aqui . Eu acho que você tem que descer até o nível de extensão para ver quanto espaço é realmente usado ?
jpmc26

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

Nota: Estas são estimativas, tornadas mais precisas com estatísticas de coleta:

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

2
Essas estatísticas podem ser null( num_rows, avg_row_len), você precisa fazer algumas análises antes através da seguinte declaraçãoANALYZE TABLE your_table COMPUTE STATISTICS
Brice

Uma análise difícil pode demorar muito!
Brice

bom trabalho em torno de quando eu não posso conferir uma tabela nenhum-tablespace
tungns304

30

Primeiro, eu geralmente advertiria que reunir estatísticas da tabela para fazer a análise de espaço é uma coisa potencialmente perigosa a se fazer. A coleta de estatísticas pode alterar os planos de consulta, principalmente se o DBA configurou um trabalho de coleta de estatísticas que usa parâmetros não padrão que sua chamada não está usando e fará com que o Oracle analise novamente as consultas que utilizam a tabela em questão, o que pode ser um desempenho. acertar. Se o DBA deixou intencionalmente algumas tabelas sem estatísticas (comum se você OPTIMIZER_MODEescolher ESCOLHER), a coleta de estatísticas pode fazer com que o Oracle pare de usar o otimizador baseado em regras e comece a usar o otimizador baseado em custos para um conjunto de consultas que podem ser um desempenho importante dor de cabeça se for feito inesperadamente na produção. Se suas estatísticas forem precisas, você pode consultar USER_TABLES(ou ALL_TABLESouDBA_TABLES) diretamente sem ligar GATHER_TABLE_STATS. Se suas estatísticas não forem precisas, provavelmente existe uma razão para isso e você não deseja perturbar o status quo.

Segundo, o equivalente mais próximo ao sp_spaceusedprocedimento do SQL Server é provavelmente o DBMS_SPACEpacote da Oracle . Tom Kyte possui um bom show_spaceprocedimento que fornece uma interface simples para este pacote e imprime informações semelhantes às que são sp_spaceusedimpressas.


8

Primeiro, reúna estatísticas do otimizador na tabela (se você ainda não o tiver):

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

AVISO: Como Justin diz em sua resposta, a coleta de estatísticas do otimizador afeta a otimização de consultas e não deve ser feita sem o devido cuidado e consideração !

Em seguida, encontre o número de blocos ocupados pela tabela nas estatísticas geradas:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • O número total de blocos alocados à tabela é de blocos + blocos vazios + num_freelist_blocks.

  • blocks é o número de blocos que realmente contêm dados.

Multiplique o número de blocos pelo tamanho do bloco em uso (geralmente 8 KB) para obter o espaço consumido - por exemplo, 17 blocos x 8 KB = 136 KB.

Para fazer isso para todas as tabelas em um esquema de uma vez:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Nota: Alterações feitas acima, depois de ler este tópico do AskTom


7

Modifiquei a consulta da WW para fornecer informações mais detalhadas:

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

Para tabelas e índices sub-particionados, podemos usar a seguinte consulta



    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 as tabelas necessárias são DBA_TABLES, DBA_EXTENTS ou DBA_SEGMENTS e DBA_DATA_FILES. Também existem versões USER_ e ALL_ para tabelas que você pode ver se não possui permissões de administração na máquina.


4

Aqui está uma variante da resposta dos WWs, inclui partições e sub-partições, conforme sugerido anteriormente, além de uma coluna para mostrar o TIPO: Tabela / Índice / LOB, etc.

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

Modifiquei a consulta para obter o tamanho do esquema por espaço de tabela.

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

Depende do que você quer dizer com "tamanho da tabela". Uma tabela não está relacionada a um arquivo específico no sistema de arquivos. Uma tabela residirá em um espaço de tabela (possivelmente vários espaços de tabela, se estiver particionado, e possivelmente vários espaços de tabela, se você também quiser levar em consideração os índices na tabela). Um espaço de tabela geralmente possui várias tabelas e pode se espalhar por vários arquivos.

Se você estiver estimando quanto espaço precisará para o crescimento futuro da tabela, então avg_row_len multiplicado pelo número de linhas da tabela (ou número de linhas que você espera da tabela) será um bom guia. Porém, a Oracle deixará algum espaço livre em cada bloco, em parte para permitir que as linhas 'cresçam' se forem atualizadas, em parte porque talvez não seja possível ajustar outra linha inteira nesse bloco (por exemplo, um bloco de 8K caberia apenas 2 linhas de 3K, embora esse seja um exemplo extremo, pois 3K é muito maior que a maioria dos tamanhos de linha). Portanto, BLOCKS (em USER_TABLES) pode ser um guia melhor.

Mas se você tivesse 200.000 linhas em uma tabela, excluiu metade delas, a tabela ainda 'possuirá' o mesmo número de blocos. Não os libera para outras tabelas usarem. Além disso, os blocos não são adicionados a uma tabela individualmente, mas em grupos chamados de 'extensão'. Portanto, geralmente haverá EMPTY_BLOCKS (também em USER_TABLES) em uma tabela.


1

Correção para tabelas particionadas:

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

Seleção simples que retorna os tamanhos brutos das tabelas, com base no tamanho do bloco, também inclui tamanho com índice

selecione table_name, (nvl ((selecione a soma (blocos) de dba_indexes a, dba_segments b em que a.index_name = b.segment_name e a.table_name = dba_tables.table_name), 0) + blocos) * 8192/1024 TotalSize, blocos * 8 tableSize de dba_tables encomende até 3


0

Achei isso um pouco mais preciso:

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
Parece um pouco com a minha resposta?
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

há mais uma opção que permite obter o tamanho "selecionar" com junções e o tamanho da tabela como opção também

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

Eu tenho a mesma variante dos últimos que calcula segmentos de dados de tabela, índices de tabela e campos de 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;

Fonte .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.