Як обчислити розмір таблиць в Oracle


128

Будучи звичним (і потенційно зіпсованим) MSSQL, мені цікаво, як я можу отримати розмір таблиць в Oracle 10g. Я переглянув його, тому зараз знаю, що у мене може бути не такий простий варіант, як sp_spaceused. І все-таки можливі відповіді, які я отримав, більшість часу застаріли або не працюють. Можливо, тому, що я не DBA за схемою, з якою працюю.

Хто-небудь має рішення та / або рекомендації?


якщо професіонал дасть відповідь зіпсований, то візьміть відповіді, які ви отримали звідси, і загорніть їх у процедуру та зателефонуйте ... dun dun duh ... sp_spaceused. У цьому дійсно мало магії.

1
@MarkBrady Можливо, не магія, але потрібні тонни таємничих знань.
jpmc26

Відповіді:


201

Вас може зацікавити цей запит. Він говорить вам, скільки місця виділяється для кожної таблиці з урахуванням індексів та будь-яких LOB у таблиці. Часто вам цікаво знати, «скільки місця займає таблиця замовлень на замовлення, включаючи будь-які індекси», а не лише саму таблицю. Ви завжди можете заглиблюватися в деталі. Зауважте, що для цього потрібен доступ до переглядів 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

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
Ця статистика може бути null( num_rows, avg_row_len), вам потрібно зробити деякий аналіз, перш ніж наступне твердженняANALYZE TABLE your_table COMPUTE STATISTICS
Бріс

Важкий аналіз їх може бути дуже довгим!
Бріс

приємна робота, коли я не можу перевірити таблицю
простору без

30

По-перше, я б, як правило, застеріг, що збирання статистичних даних таблиці для аналізу простору є потенційно небезпечною справою. Збір статистики може змінити плани запитів, особливо якщо DBA налаштував завдання збору статистики, що використовує параметри, що не використовуються за замовчуванням, які ваш виклик не використовує, і призведе до того, що Oracle повторно розбере запити, які використовують відповідну таблицю, яка може бути результативним хіт. Якщо DBA навмисно залишив деякі таблиці без статистичних даних (загальноприйнятим, якщо OPTIMIZER_MODEце CHOOSE), збір статистики може призвести до того, що Oracle перестане використовувати оптимізатор на основі правил і почати використовувати оптимізатор на основі витрат для набору запитів, які можуть стати головною ефективністю головний біль, якщо це робиться несподівано на виробництві. Якщо ваші статистичні дані точні, ви можете запитувати USER_TABLES(або ALL_TABLESабо)DBA_TABLES) безпосередньо без дзвінків GATHER_TABLE_STATS. Якщо ваші статистичні дані не точні, можливо, це є причиною, і ви не хочете порушувати статус-кво.

По-друге, найближчий еквівалент sp_spaceusedпроцедурі SQL Server - це, ймовірно, DBMS_SPACEпакет Oracle . Том 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.

  • блоки - це кількість блоків, які фактично містять дані.

Помножте кількість блоків на розмір використовуваного блоку (зазвичай 8 КБ), щоб отримати витрачений простір - наприклад, 17 блоків х 8 КБ = 136 КБ.

Щоб зробити це для всіх таблиць на схемі одночасно:

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

Ось варіант відповіді 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;

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 набагато більший, ніж більшість розмірів рядків). Тож BLOCKS (у USER_TABLES) може бути кращим посібником.

Але якби у вас було 200 000 рядків у таблиці, видалили їх половину, тоді таблиця все одно буде «володіти» однаковою кількістю блоків. Він не випускає їх для використання в інших таблицях. Також блоки не додаються до таблиці окремо, а в групах, які називаються "масштабом". Таким чином, загалом у таблиці буде 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

Простий вибір, який повертає необроблені розміри таблиць, виходячи з розміру блоку, також включає розмір з індексом

виберіть table_name, (nvl ((виберіть суму (блоки) з dba_indexes a, dba_segments b, де a.index_name = b.segment_name та a.table_name = dba_tables.table_name), 0) + блоки) * 8192/1024 TotalSize, блоки * 8 tableSize від dba_tables порядку на 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
Дещо схожа на мою відповідь?
ВВ.

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

є ще одна опція, яка дозволяє отримати розмір "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);

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

Джерело .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.