it-swarm.com.de

Wie berechne ich die Tabellengröße in Oracle?

Da ich an MSSQL gewöhnt bin (und möglicherweise von MSSQL verdorben werde), frage ich mich, wie ich in Oracle 10g Tabellengröße erreichen kann. Ich habe es gegoogelt und bin mir jetzt bewusst, dass ich möglicherweise keine so einfache Option wie sp_spaceused habe. Trotzdem sind die möglichen Antworten, die ich erhalten habe, die meiste Zeit veraltet oder funktionieren nicht. Wahrscheinlich, weil ich keinen DBA für das Schema habe, mit dem ich arbeite.

Hätte jemand Lösungen und/oder Empfehlungen?

121
Rollo Tomazzi

Diese Abfrage könnte Sie interessieren. Hier erfahren Sie, wie viel Speicherplatz für jede Tabelle unter Berücksichtigung der Indizes und etwaiger LOBs in der Tabelle zugewiesen ist. Häufig interessiert Sie nicht nur die Tabelle selbst, sondern auch, wie viel Speicherplatz die Tabelle "Bestellung" einschließlich aller Indizes beansprucht. Sie können immer in die Details eintauchen. Beachten Sie, dass hierfür Zugriff auf die DBA_ * -Ansichten erforderlich ist.

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

Hinweis: Dies sind Schätzungen, die mit der Erfassung von Statistiken präzisiert wurden:

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

Zunächst einmal würde ich generell darauf hinweisen, dass das Sammeln von Tabellenstatistiken für die Speicherplatzanalyse eine potenziell gefährliche Aufgabe ist. Das Sammeln von Statistiken kann Abfragepläne ändern, insbesondere wenn der DBA einen Statistik-Erfassungsjob konfiguriert hat, der nicht standardmäßige Parameter verwendet, die Ihr Aufruf nicht verwendet, und Oracle veranlasst, Abfragen, die die fragliche Tabelle verwenden, neu zu analysieren, was eine Leistung sein kann schlagen. Wenn der DBA absichtlich einige Tabellen ohne Statistik belassen hat (häufig, wenn OPTIMIZER_MODE CHOOSE ist), kann das Sammeln von Statistiken dazu führen, dass Oracle den regelbasierten Optimierer nicht mehr verwendet und den kostenbasierten Optimierer für eine Reihe von Abfragen verwendet Dies kann zu erheblichen Leistungsproblemen führen, wenn dies in der Produktion unerwartet erfolgt. Wenn Ihre Statistiken korrekt sind, können Sie USER_TABLES (Oder ALL_TABLES Oder DBA_TABLES) Direkt abfragen, ohne GATHER_TABLE_STATS Aufzurufen. Wenn Ihre Statistiken nicht genau sind, gibt es wahrscheinlich einen Grund dafür und Sie möchten den Status Quo nicht stören.

Zweitens ist das Paket sp_spaceused Von Oracle wahrscheinlich das am ehesten dem SQL Server-Verfahren DBMS_SPACE Entsprechende. Tom Kyte hat eine Nice show_space - Prozedur , die eine einfache Schnittstelle zu diesem Paket bietet und Informationen ausgibt, die denen von sp_spaceused Ähneln.

29
Justin Cave

Sammeln Sie zunächst die Optimierungsstatistiken auf dem Tisch (falls Sie dies noch nicht getan haben):

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

WARNUNG: Wie Justin in seiner Antwort sagt, wirkt sich das Sammeln von Optimierungsstatistiken auf die Abfrageoptimierung aus und sollte nicht ohne Sorgfalt und Rücksichtnahme erfolgen !

Finden Sie dann die Anzahl der von der Tabelle belegten Blöcke aus den generierten Statistiken:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • Die Gesamtzahl der der Tabelle zugewiesenen Blöcke ist blocks + empty_blocks + num_freelist_blocks.

  • blocks ist die Anzahl der Blöcke, die tatsächlich Daten enthalten.

Multiplizieren Sie die Anzahl der Blöcke mit der verwendeten Blockgröße (normalerweise 8 KB), um den belegten Speicherplatz zu erhalten - z. 17 Blöcke x 8 KB = 136 KB.

So führen Sie dies für alle Tabellen in einem Schema gleichzeitig aus:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Hinweis: Nach dem Lesen von diesem AskTom-Thread wurden an den obigen Änderungen Änderungen vorgenommen

8
Tony Andrews

Ich habe die WW-Abfrage geändert, um detailliertere Informationen bereitzustellen:

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

Für subpartitionierte Tabellen und Indizes können wir die folgende Abfrage verwenden



    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
rratina

IIRC die Tabellen, die Sie benötigen, sind DBA_TABLES, DBA_EXTENTS oder DBA_SEGMENTS und DBA_DATA_FILES. Es gibt auch USER_- und ALL_-Versionen für Tabellen, die angezeigt werden, wenn Sie keine Administratorrechte auf dem Computer haben.

Hier ist eine Variante der Antwort von WWs, die Partitionen und Unterpartitionen enthält, wie andere oben vorgeschlagen haben, sowie eine Spalte zur Anzeige des TYPE: Table/Index/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
ss64
select segment_name,segment_type,bytes/1024/1024 MB
from dba_segments
where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;
3
bronx

Korrektur für partitionierte Tabellen:

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

Ich habe die Abfrage geändert, um die Schemagröße pro Tablespace zu ermitteln.

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

Kommt darauf an, was Sie unter "Tischgröße" verstehen. Eine Tabelle bezieht sich nicht auf eine bestimmte Datei im Dateisystem. Eine Tabelle befindet sich in einem Tabellenbereich (möglicherweise mehrere Tabellenbereiche, wenn sie partitioniert ist, und möglicherweise mehrere Tabellenbereiche, wenn Sie auch Indizes für die Tabelle berücksichtigen möchten). Ein Tablespace enthält häufig mehrere Tabellen und kann über mehrere Dateien verteilt sein.

Wenn Sie schätzen, wie viel Speicherplatz Sie für das zukünftige Wachstum der Tabelle benötigen, ist avg_row_len multipliziert mit der Anzahl der Zeilen in der Tabelle (oder der Anzahl der Zeilen, die Sie in der Tabelle erwarten) ein guter Anhaltspunkt. Oracle lässt jedoch für jeden Block etwas Platz frei, teilweise, damit die Zeilen 'wachsen', wenn sie aktualisiert werden, teilweise, weil es möglicherweise nicht möglich ist, eine weitere ganze Zeile in diesen Block einzupassen (z. B. würde ein 8-KB-Block nur 2 Zeilen aufnehmen von 3K, obwohl dies ein extremes Beispiel wäre, da 3K viel größer ist als die meisten Zeilengrößen). BLOCKS (in USER_TABLES) könnten daher eine bessere Anleitung sein.

Wenn Sie jedoch 200.000 Zeilen in einer Tabelle hätten und die Hälfte davon löschten, würde die Tabelle immer noch die gleiche Anzahl von Blöcken besitzen. Sie werden nicht für andere Tabellen freigegeben. Außerdem werden Blöcke nicht einzeln, sondern in Gruppen, die als "Extent" bezeichnet werden, zu einer Tabelle hinzugefügt. In der Regel gibt es also EMPTY_BLOCKS (auch in USER_TABLES) in einer Tabelle.

1
Gary Myers

Ich fand das etwas genauer:

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
0
Geoffrey Musafu
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 ;
0
Vijay Chettiar

Einfache Auswahl, die die Rohgrößen der Tabellen basierend auf der Blockgröße zurückgibt, schließt auch Größe mit Index ein

wähle Tabellenname, (nvl ((wähle Summe (Blöcke) aus dba_indexes a, dba_segments b mit a.index_name = b.segment_name und a.table_name = dba_tables.table_name), 0) + Blöcke) * 8192/1024 TotalSize, Blöcke * 8 tableSize von dba_tables um 3 ordnen

0
Noam