Как рассчитать размер таблиц в Oracle - PullRequest
120 голосов
/ 05 ноября 2008

Привыкая (и потенциально испорченная) к MSSQL, мне интересно, как я могу получить размер таблиц в Oracle 10g. Я гуглил его, так что теперь я знаю, что у меня может быть не такой простой вариант, как у sp_spaceused. Тем не менее, потенциальные ответы, которые я получил, в большинстве случаев устарели или не работают. Возможно, потому что я не администратор базы данных в схеме, с которой я работаю.

Есть ли у кого-нибудь решения или рекомендации?

Ответы [ 17 ]

195 голосов
/ 06 ноября 2008

Вас может заинтересовать этот запрос. Он сообщает вам, сколько места выделено для каждой таблицы с учетом индексов и любых больших объектов в таблице. Часто вам интересно знать, сколько места занимает таблица заказа на покупку, включая любые индексы, а не только сама таблица. Вы всегда можете вникнуть в детали. Обратите внимание, что для этого требуется доступ к представлениям 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
;
36 голосов
/ 11 апреля 2012
-- 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');
29 голосов
/ 05 ноября 2008

Прежде всего, я бы вообще предупредил, что сбор статистики таблицы для анализа пространства - потенциально опасная вещь. Сбор статистики может изменить планы запросов, особенно если администратор баз данных настроил задание по сбору статистики, которое использует параметры не по умолчанию, которые не используются вашим вызовом, и заставит Oracle повторно анализировать запросы, использующие данную таблицу, что может быть производительностью. удар. Если администратор базы данных намеренно оставил некоторые таблицы без статистики (обычно, если OPTIMIZER_MODE - ВЫБРАТЬ), сбор статистики может привести к тому, что Oracle прекратит использование оптимизатора на основе правил и начнет использовать оптимизатор на основе затрат для набора запросов, которые могут быть главная головная боль производительности, если это сделано неожиданно в производстве. Если ваша статистика точна, вы можете запросить USER_TABLES (или ALL_TABLES или DBA_TABLES) напрямую, не вызывая GATHER_TABLE_STATS. Если ваша статистика не точна, возможно, для этого есть причина, и вы не хотите нарушать статус-кво.

Во-вторых, наиболее близким эквивалентом процедуры sp_spaceused SQL Server, вероятно, является пакет Oracle DBMS_SPACE. У Тома Кайта есть хорошая show_space процедура , которая обеспечивает простой интерфейс к этому пакету и распечатывает информацию, аналогичную той, которую печатает sp_spaceused.

8 голосов
/ 05 ноября 2008

Сначала соберите статистику оптимизатора на столе (если вы этого еще не сделали):

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';
  • Общее количество блоков, выделенных для таблицы: blocks + empty_blocks + num_freelist_blocks.

  • блоков - это количество блоков, которые фактически содержат данные.

Умножьте количество блоков на используемый размер блока (обычно 8 КБ), чтобы получить занимаемое пространство - например, 17 блоков x 8 КБ = 136 КБ.

Чтобы сделать это сразу для всех таблиц в схеме:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Примечание: изменения, внесенные в вышеприведенное после прочтения этой ветки AskTom

6 голосов
/ 19 декабря 2012

Для подразделяющихся таблиц и индексов мы можем использовать следующий запрос



    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
    ;

6 голосов
/ 21 мая 2013

Я изменил запрос 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
/
5 голосов
/ 05 ноября 2008

IIRC необходимые вам таблицы: DBA_TABLES, DBA_EXTENTS или DBA_SEGMENTS и DBA_DATA_FILES. Существуют также версии USER_ и ALL_ для этих таблиц, которые можно увидеть, если у вас нет прав администратора на компьютере.

3 голосов
/ 16 апреля 2014
select segment_name,segment_type,bytes/1024/1024 MB
from dba_segments
where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;
3 голосов
/ 27 марта 2013

Вот вариант ответа 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;
1 голос
/ 06 ноября 2008

Зависит от того, что вы подразумеваете под «размером таблицы». Таблица не относится к конкретному файлу в файловой системе. Таблица будет находиться в табличном пространстве (возможно, в нескольких табличных пространствах, если она разбита на разделы, и, возможно, в нескольких табличных пространствах, если вы также хотите учесть индексы в таблице). Табличное пространство часто содержит несколько таблиц и может быть распределено по нескольким файлам.

Если вы подсчитываете, сколько места вам понадобится для будущего роста таблицы, тогда avg_row_len, умноженное на количество строк в таблице (или количество строк, ожидаемых в таблице), будет хорошим ориентиром. Но Oracle оставит свободное пространство в каждом блоке, частично для того, чтобы строки могли «расти», если они будут обновлены, частично потому, что может оказаться невозможным разместить еще одну целую строку в этом блоке (например, блок 8K будет соответствовать только 2 строкам 3K, хотя это был бы экстремальный пример, поскольку 3K намного больше, чем большинство размеров строк). Так что BLOCKS (в USER_TABLES) может быть лучшим руководством.

Но если бы у вас было 200 000 строк в таблице, и половина из них была удалена, то таблица все равно «имела бы» такое же количество блоков. Это не освобождает их для использования другими таблицами. Кроме того, блоки не добавляются в таблицу по отдельности, а в группы, называемые «экстент». Поэтому, как правило, в таблице будет EMPTY_BLOCKS (также в USER_TABLES).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...