Come calcolo le dimensioni delle tabelle in Oracle


128

Essendo abituato (e potenzialmente viziato da) MSSQL, mi chiedo come posso arrivare alle dimensioni dei tavoli in Oracle 10g. L'ho cercato su Google, quindi ora sono consapevole che potrei non avere un'opzione facile come sp_spaceused. Tuttavia le risposte potenziali che ho ricevuto sono per lo più obsolete o non funzionano. Probabilmente perché non sono un DBA sullo schema con cui sto lavorando.

Qualcuno avrebbe soluzioni e o raccomandazioni?


se avere un proc dà la risposta viene rovinato, quindi prendi le risposte che hai da qui e avvolgile in una procedura e chiamale ... dun dun duh ... sp_spaceused. C'è davvero poca magia.

1
@MarkBrady Forse non è magico, ma è richiesta una tonnellata di conoscenza arcana.
jpmc26,

Risposte:


201

Potresti essere interessato a questa query. Indica la quantità di spazio allocata per ogni tabella tenendo conto degli indici e degli eventuali LOB sulla tabella. Spesso sei interessato a sapere "Quanti spazi occupa la tabella degli ordini di acquisto, inclusi eventuali indici" anziché solo la tabella stessa. Puoi sempre approfondire i dettagli. Si noti che ciò richiede l'accesso alle viste 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
Si noti che questa risposta conta i segmenti, che non fanno distinzione tra spazio attualmente in uso e spazio precedentemente utilizzato. Apparentemente, una volta assegnato un segmento a una tabella, viene sempre assegnato a una tabella, anche se lo spazio viene liberato. Vedi qui . Immagino che devi scendere al livello di estensione per vedere quanto spazio viene effettivamente utilizzato ?
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: queste sono stime, rese più accurate con le statistiche di raccolta:

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

2
Queste statistiche potrebbero essere null( num_rows, avg_row_len), è necessario effettuare alcune analisi prima tramite la seguente dichiarazioneANALYZE TABLE your_table COMPUTE STATISTICS
Brice

L'analisi difficile di questi potrebbe essere molto lunga!
Brice,

bello aggirare quando non riesco a controllare una tabella nessuno-tablespace
tungns304

30

Prima di tutto, vorrei generalmente mettere in guardia sul fatto che raccogliere statistiche sui tavoli per fare analisi dello spazio sia una cosa potenzialmente pericolosa da fare. La raccolta delle statistiche può modificare i piani di query, in particolare se il DBA ha configurato un processo di raccolta delle statistiche che utilizza parametri non predefiniti che la chiamata non sta utilizzando e indurrà Oracle a analizzare nuovamente le query che utilizzano la tabella in questione che può essere una prestazione colpire. Se il DBA ha lasciato intenzionalmente alcune tabelle senza statistiche (comune se si OPTIMIZER_MODEè SCEGLI), la raccolta di statistiche può far smettere Oracle di utilizzare l'ottimizzatore basato su regole e iniziare a utilizzare l'ottimizzatore basato sui costi per una serie di query che possono essere prestazioni importanti mal di testa se viene fatto inaspettatamente in produzione. Se le tue statistiche sono accurate, puoi eseguire una query USER_TABLES(o ALL_TABLESoDBA_TABLES) direttamente senza chiamare GATHER_TABLE_STATS. Se le tue statistiche non sono accurate, probabilmente c'è una ragione per questo e non vuoi disturbare lo status quo.

In secondo luogo, l'equivalente più vicino alla sp_spaceusedprocedura di SQL Server è probabilmente il DBMS_SPACEpacchetto Oracle . Tom Kyte ha una bella show_spaceprocedura che fornisce una semplice interfaccia a questo pacchetto e stampa informazioni simili a quelle sp_spaceusedstampate.


8

Innanzitutto, raccogli le statistiche dell'ottimizzatore sul tavolo (se non l'hai già fatto):

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

ATTENZIONE: come dice Justin nella sua risposta, la raccolta di statistiche sull'ottimizzatore influisce sull'ottimizzazione delle query e non dovrebbe essere eseguita senza la dovuta cura e considerazione !

Quindi trova il numero di blocchi occupati dalla tabella dalle statistiche generate:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • Il numero totale di blocchi assegnati alla tabella è blocchi + blocchi_vuoto + blocco_elenco_ num.

  • blocchi è il numero di blocchi che contengono effettivamente dati.

Moltiplicare il numero di blocchi per la dimensione del blocco in uso (di solito 8 KB) per ottenere lo spazio consumato, ad esempio 17 blocchi x 8 KB = 136 KB.

Per fare ciò per tutte le tabelle in uno schema contemporaneamente:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Nota: modifiche apportate a quanto sopra dopo aver letto questo thread AskTom


7

Ho modificato la query del WW per fornire informazioni più dettagliate:

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

Per le tabelle e gli indici sub partizionati possiamo usare la seguente query



    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 le tabelle necessarie sono DBA_TABLES, DBA_EXTENTS o DBA_SEGMENTS e DBA_DATA_FILES. Esistono anche versioni USER_ e ALL_ di queste per le tabelle che puoi vedere se non disponi delle autorizzazioni di amministrazione sulla macchina.


4

Ecco una variante della risposta WWs, include partizioni e sotto-partizioni come altri hanno suggerito sopra, oltre a una colonna per mostrare il TIPO: Tabella / Indice / LOB ecc

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

Ho modificato la query per ottenere la dimensione dello schema per tablespace ..

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

Dipende da cosa intendi per "dimensione della tabella". Una tabella non riguarda un file specifico nel file system. Una tabella risiederà in un tablespace (possibilmente più tablespace se è partizionato e possibilmente più tablespace se si desidera prendere in considerazione anche gli indici della tabella). Uno spazio tabella contiene spesso più tabelle e può essere suddiviso su più file.

Se stai valutando lo spazio necessario per la crescita futura della tabella, allora avg_row_len moltiplicato per il numero di righe nella tabella (o il numero di righe che ti aspetti nella tabella) sarà una buona guida. Ma Oracle lascerà un po 'di spazio libero su ciascun blocco, in parte per consentire alle righe di "crescere" se vengono aggiornate, in parte perché potrebbe non essere possibile adattare un'altra intera riga su quel blocco (ad esempio un blocco da 8 KB si adatta solo a 2 righe di 3K, anche se questo sarebbe un esempio estremo in quanto 3K è molto più grande della maggior parte delle dimensioni delle righe). Quindi BLOCKS (in USER_TABLES) potrebbe essere una guida migliore.

Ma se avessi 200.000 righe in una tabella, eliminandone la metà, la tabella continuerebbe a "possedere" lo stesso numero di blocchi. Non li rilascia per altri tavoli da usare. Inoltre, i blocchi non vengono aggiunti a una tabella singolarmente, ma in gruppi chiamati "estensione". Quindi ci saranno generalmente EMPTY_BLOCKS (anche in USER_TABLES) in una tabella.


1

Correzione per le tabelle partizionate:

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

La selezione semplice che restituisce le dimensioni non elaborate delle tabelle, in base alla dimensione del blocco, include anche la dimensione con indice

seleziona table_name, (nvl ((seleziona sum (blocchi) da dba_indexes a, dba_segments b dove a.index_name = b.segment_name e a.table_name = dba_tables.table_name), 0) + blocchi) * 8192/1024 TotalSize, blocchi * 8 tableSize da dba_tables ordina per 3


0

Ho trovato questo per essere un po 'più 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
Sembra un po 'la mia risposta?
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

c'è un'altra opzione che consente di ottenere la dimensione "seleziona" con i join e anche la dimensione della tabella come opzione

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

Ho la stessa variante delle ultime che calcola segmenti di dati di tabella, indici di tabella e campi 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 .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.