Bagaimana cara menghitung ukuran tabel di Oracle

128

Digunakan untuk (dan berpotensi dimanjakan oleh) MSSQL, saya bertanya-tanya bagaimana saya bisa mendapatkan ukuran tabel di Oracle 10g. Saya telah mencarinya di Google jadi saya sekarang sadar bahwa saya mungkin tidak memiliki pilihan semudah sp_spaceused. Tetap saja jawaban potensial yang saya dapatkan sebagian besar sudah usang atau tidak berfungsi. Mungkin karena saya bukan DBA di skema saya bekerja dengan.

Adakah yang punya solusi dan atau rekomendasi?

Rollo Tomazzi
sumber
jika memiliki proc memberikan jawaban sedang manja, maka ambil jawaban yang Anda dapatkan dari sini dan bungkus menjadi sebuah prosedur dan menyebutnya ... dun dun duh ... sp_spaceused. Benar-benar ada sedikit keajaiban untuk itu.
1
@ MarkBrady Mungkin bukan sihir, tapi banyak pengetahuan misterius diperlukan.
jpmc26

Jawaban:

201

Anda mungkin tertarik dengan pertanyaan ini. Ini memberi tahu Anda berapa banyak ruang yang dialokasikan untuk setiap tabel dengan mempertimbangkan indeks dan setiap LOB di atas meja. Seringkali Anda tertarik untuk mengetahui "Berapa banyak ruang yang dibutuhkan tabel Purchase Order, termasuk indeks apa pun" daripada hanya tabel itu sendiri. Anda selalu dapat mempelajari detailnya. Perhatikan bahwa ini membutuhkan akses ke tampilan 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
;
WW.
sumber
1
Perhatikan bahwa jawaban ini menghitung segmen, yang tidak membedakan antara ruang yang saat ini digunakan vs ruang yang sebelumnya digunakan. Rupanya, begitu sebuah segmen ditugaskan ke sebuah tabel, itu selalu ditugaskan ke sebuah tabel, bahkan jika ruang dibebaskan. Lihat di sini . Saya kira Anda harus turun ke tingkat sejauh untuk melihat berapa banyak ruang yang sebenarnya digunakan ?
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.
;

Catatan: Ini adalah perkiraan, dibuat lebih akurat dengan statistik pengumpulan:

exec dbms_utility.analyze_schema(user,'COMPUTE');
pengemis
sumber
2
Statistik ini mungkin null( num_rows, avg_row_len), Anda perlu membuat beberapa analisis sebelum melalui pernyataan berikutANALYZE TABLE your_table COMPUTE STATISTICS
Brice
Analisis yang sulit ini mungkin sangat lama!
Brice
kerja bagus di sekitar ketika saya tidak bisa memeriksa tabel none-tablespace
tungns304
30

Pertama, saya biasanya memperingatkan bahwa mengumpulkan statistik tabel untuk melakukan analisis ruang adalah hal yang berpotensi berbahaya untuk dilakukan. Mengumpulkan statistik dapat mengubah rencana kueri, terutama jika DBA telah mengonfigurasi pekerjaan pengumpulan statistik yang menggunakan parameter non-default yang tidak digunakan panggilan Anda, dan akan menyebabkan Oracle mem-parsing ulang kueri yang menggunakan tabel yang dipermasalahkan yang dapat menjadi kinerja memukul. Jika DBA sengaja meninggalkan beberapa tabel tanpa statistik (umum jika Anda OPTIMIZER_MODEPILIH), mengumpulkan statistik dapat menyebabkan Oracle berhenti menggunakan pengoptimal berbasis aturan dan mulai menggunakan pengoptimal berbasis biaya untuk serangkaian pertanyaan yang dapat menjadi kinerja utama sakit kepala jika dilakukan secara tak terduga dalam produksi. Jika statistik Anda akurat, Anda dapat meminta USER_TABLES(atau ALL_TABLESatauDBA_TABLES) langsung tanpa menelepon GATHER_TABLE_STATS. Jika statistik Anda tidak akurat, mungkin ada alasan untuk itu dan Anda tidak ingin mengganggu status quo.

Kedua, setara terdekat dengan sp_spaceusedprosedur SQL Server kemungkinan DBMS_SPACEpaket Oracle . Tom Kyte memiliki show_spaceprosedur bagus yang menyediakan antarmuka sederhana untuk paket ini dan mencetak informasi yang mirip dengan apa yang sp_spaceuseddicetak.

Gua Justin
sumber
8

Pertama, kumpulkan statistik pengoptimal di atas meja (jika belum):

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

PERINGATAN: Seperti yang dikatakan Justin dalam jawabannya, mengumpulkan statistik pengoptimal memengaruhi pengoptimalan kueri dan tidak boleh dilakukan tanpa perhatian dan pertimbangan !

Kemudian temukan jumlah blok yang ditempati oleh tabel dari statistik yang dihasilkan:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • Jumlah total blok yang dialokasikan ke tabel adalah blok + empty_blocks + num_freelist_blocks.

  • blok adalah jumlah blok yang sebenarnya mengandung data.

Lipat gandakan jumlah blok dengan ukuran blok yang digunakan (biasanya 8KB) untuk mendapatkan ruang yang dikonsumsi - misalnya 17 blok x 8KB = 136KB.

Untuk melakukan ini untuk semua tabel dalam skema sekaligus:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Catatan: Perubahan yang dibuat di atas setelah membaca utas AskTom ini

Tony Andrews
sumber
7

Saya memodifikasi kueri WW untuk memberikan informasi lebih rinci:

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
/
Sergey Stadnik
sumber
6

Untuk tabel dan indeks sub-partisi kami dapat menggunakan kueri berikut



    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
    ;
rratina
sumber
5

IIRC tabel yang Anda butuhkan adalah DBA_TABLES, DBA_EXTENTS atau DBA_SEGMENTS dan DBA_DATA_FILES. Ada juga versi USER_ dan ALL_ untuk tabel ini yang bisa Anda lihat jika Anda tidak memiliki izin administrasi di mesin.

ConcernedOfTunbridgeWells
sumber
4

Inilah varian jawaban WWs, ini mencakup partisi dan sub-partisi seperti yang disarankan orang lain di atas, ditambah kolom untuk menunjukkan JENIS: Tabel / Indeks / LOB dll.

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;
SS64
sumber
3
select segment_name,segment_type,bytes/1024/1024 MB
from dba_segments
where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;
bronx
sumber
2

Saya memodifikasi kueri untuk mendapatkan ukuran skema 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
;
Najee Ghanim
sumber
1

Tergantung apa yang Anda maksud dengan "ukuran tabel". Tabel tidak berhubungan dengan file tertentu pada sistem file. Sebuah tabel akan berada di tablespace (mungkin beberapa tablespace jika dipartisi, dan mungkin beberapa tablespace jika Anda juga ingin memperhitungkan indeks akun pada tabel). Tablespace sering memiliki beberapa tabel di dalamnya, dan dapat tersebar di beberapa file.

Jika Anda memperkirakan berapa banyak ruang yang Anda perlukan untuk pertumbuhan tabel di masa mendatang, maka avg_row_len dikalikan dengan jumlah baris dalam tabel (atau jumlah baris yang Anda harapkan dalam tabel) akan menjadi panduan yang baik. Tetapi Oracle akan membiarkan beberapa ruang kosong di setiap blok, sebagian untuk memungkinkan baris 'tumbuh' jika diperbarui, sebagian karena tidak mungkin untuk memasukkan seluruh baris lain pada blok itu (misalnya blok 8K hanya akan cocok dengan 2 baris 3K, meskipun itu akan menjadi contoh ekstrim karena 3K jauh lebih besar daripada ukuran baris paling). Jadi BLOCKS (dalam USER_TABLES) mungkin menjadi panduan yang lebih baik.

Tetapi jika Anda memiliki 200.000 baris dalam sebuah tabel, menghapus setengahnya, maka tabel tersebut masih 'memiliki' jumlah blok yang sama. Itu tidak melepaskan mereka untuk tabel lain untuk digunakan. Juga, blok tidak ditambahkan ke tabel secara individual, tetapi dalam kelompok yang disebut 'luas'. Jadi pada umumnya akan ada EMPTY_BLOCKS (juga di USER_TABLES) dalam sebuah tabel.

Gary Myers
sumber
1

Koreksi untuk tabel yang dipartisi:

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
;
rratina
sumber
0

Pilih sederhana yang mengembalikan ukuran mentah tabel, berdasarkan ukuran blok, juga termasuk ukuran dengan indeks

pilih table_name, (nvl ((pilih jumlah (blok) dari dba_indexes a, dba_segments b di mana a.index_name = b.segment_name dan a.table_name = dba_tables.table_name), 0) + blok) * 8192/1024 TotalSize, blok * 8 tableSize dari dba_tables dipesan oleh 3

Noam
sumber
0

Saya menemukan ini sedikit lebih akurat:

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
Geoffrey Musafu
sumber
7
Sepertinya jawaban saya?
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 ;
Vijay Chettiar
sumber
-2

ada satu opsi lagi yang memungkinkan untuk mendapatkan ukuran "pilih" dengan gabungan, dan ukuran tabel sebagai opsi juga

-- 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);
mrvlad
sumber
-3

Saya memiliki varian yang sama dengan yang terakhir yang menghitung segmen data tabel, indeks tabel, dan blob-bidang:

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;

Sumber .

pengguna2498491
sumber