Oracle'da tablo boyutunu nasıl hesaplarım


128

MSSQL'e alışkın olduğum (ve potansiyel olarak şımartıldığı), Oracle 10g'de tablo boyutuna nasıl ulaşabileceğimi merak ediyorum. Googledim, bu yüzden artık sp_spaceused kadar kolay bir seçeneğim olmayabileceğinin farkındayım. Yine de aldığım olası cevaplar çoğu zaman modası geçmiş veya işe yaramıyor. Muhtemelen çalıştığım şemada DBA olmadığım için.

Çözümleri ve / veya önerileri olan var mı?


Eğer bir proc verdirmek cevabı bozuyorsa, buradan aldığınız cevapları bir prosedüre sarın ve buna ... dun dun duh ... sp_spaceused deyin. Gerçekten çok az sihir var.

1
@MarkBrady Belki sihir değil, ama bir ton gizemli bilgi gerekiyor.
jpmc26

Yanıtlar:


201

Bu sorgu ilginizi çekebilir. Tablodaki indeksleri ve herhangi bir LOB'u hesaba katarak her tablo için ne kadar alan ayrıldığını size söyler. Genellikle, sadece tablonun kendisinden ziyade "Satın Alma Siparişi tablosunun herhangi bir indeks dahil olmak üzere ne kadar yer kapladığını" bilmekle ilgilenirsiniz. Her zaman ayrıntılara girebilirsiniz. Bunun DBA_ * görünümlerine erişim gerektirdiğini unutmayın.

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
Bu cevabın, şu anda kullanımda olan ve daha önce kullanımda olan alan arasında ayrım yapmayan segmentleri saydığını unutmayın. Görünüşe göre, bir segment bir tabloya atandığında, alan boşaltılsa bile her zaman bir tabloya atanır. Buraya bakın . Sanırım gerçekte ne kadar alan kullanıldığını görmek için kapsam seviyesine inmeniz gerekiyor ?
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.
;

Not: Bunlar tahminlerdir ve istatistik toplayarak daha doğru hale getirilir:

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

2
Bu istatistikler null( num_rows, avg_row_len) olabilir, daha önce aşağıdaki ifadeyle bazı analizler yapmanız gerekirANALYZE TABLE your_table COMPUTE STATISTICS
Brice

Bunları zor analiz etmek çok uzun sürebilir!
Brice

Tablo boşluğu olmayan bir tabloyu kontrol edemediğimde iyi çalışma
tungns304

30

Öncelikle, alan analizi yapmak için tablo istatistiklerinin toplanmasının potansiyel olarak tehlikeli bir şey olduğu konusunda genel olarak uyarırım. İstatistiklerin toplanması, özellikle DBA çağrınızın kullanmadığı varsayılan olmayan parametreleri kullanan bir istatistik toplama işi yapılandırdıysa ve Oracle'ın söz konusu tabloyu kullanan ve performans olabilecek sorguları yeniden ayrıştırmasına neden olursa, sorgu planlarını değiştirebilir. çarptı. DBA kasıtlı olarak bazı tabloları istatistiksiz bıraktıysa (sizin OPTIMIZER_MODESEÇİLMİŞ ise yaygındır ), istatistik toplamak Oracle'ın kural tabanlı optimize ediciyi kullanmayı bırakmasına ve büyük bir performans olabilecek bir dizi sorgu için maliyet tabanlı optimize ediciyi kullanmaya başlamasına neden olabilir. üretimde beklenmedik şekilde yapılırsa baş ağrısı. İstatistikleriniz doğruysa, sorgulayabilirsiniz USER_TABLES(veya ALL_TABLESveyaDBA_TABLES) doğrudan aramadan GATHER_TABLE_STATS. İstatistikleriniz doğru değilse, muhtemelen bunun bir nedeni vardır ve mevcut durumu bozmak istemezsiniz.

İkinci olarak, SQL Server sp_spaceusedprosedürüne en yakın eşdeğer Oracle'ın DBMS_SPACEpaketidir. Tom Kyte, bu pakete basit bir arayüz sağlayan ve yazdırılana benzer bilgileri yazdıran güzel bir show_spaceprosedüre sahiptir sp_spaceused.


8

Öncelikle, tablodaki optimizasyon istatistikleri toplayın (henüz yapmadıysanız):

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

UYARI: Justin'in cevabında dediği gibi, iyileştirici istatistiklerini toplamak sorgu optimizasyonunu etkiler ve gerekli özen ve dikkat gösterilmeden yapılmamalıdır !

Ardından, oluşturulan istatistiklerden tablonun kapladığı blok sayısını bulun:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • Tabloya tahsis edilen toplam blok sayısı bloklar + boş_bloklar + serbest_listesi_sayısıdır.

  • bloklar, gerçekte veri içeren blok sayısıdır.

Kullanılan alanı elde etmek için blok sayısını kullanımdaki blok boyutuyla (genellikle 8KB) çarpın - örneğin 17 blok x 8KB = 136KB.

Bunu bir şemadaki tüm tablolar için aynı anda yapmak için:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Not: Bu AskTom başlığını okuduktan sonra yukarıda yapılan değişiklikler


7

Daha ayrıntılı bilgi sağlamak için WW sorgusunu değiştirdim:

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

Alt bölümlenmiş tablolar ve dizinler için aşağıdaki sorguyu kullanabiliriz



    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, ihtiyacınız olan tablolar DBA_TABLES, DBA_EXTENTS veya DBA_SEGMENTS ve DBA_DATA_FILES'dir. Makinede yönetim izinleriniz olup olmadığını görebileceğiniz tablolar için bunların USER_ ve ALL_ sürümleri de vardır.


4

Bu, WWs cevabının bir çeşididir, yukarıdaki diğerlerinin önerdiği gibi bölümler ve alt bölümler, ayrıca TÜRÜ gösteren bir sütun içerir: Tablo / Dizin / LOB vb.

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

Tablo alanı başına şema boyutunu almak için sorguyu değiştirdim ..

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

"Masa boyutu" ile ne demek istediğine bağlı. Bir tablo, dosya sistemindeki belirli bir dosyayla ilgili değildir. Bir tablo bir tablo alanında bulunur (bölümlenmişse muhtemelen birden çok tablo alanı ve tablodaki dizinleri de hesaba katmak istiyorsanız muhtemelen birden çok tablo alanı). Bir tablo alanında genellikle birden çok tablo bulunur ve birden çok dosyaya yayılabilir.

Tablonun gelecekteki büyümesi için ne kadar alana ihtiyacınız olacağını tahmin ediyorsanız, avg_row_len ile tablodaki satır sayısı (veya tabloda beklediğiniz satır sayısı) çarpılması iyi bir kılavuz olacaktır. Ancak Oracle, kısmen satırların güncellenmesi halinde 'büyümesine' izin vermek için her blokta bir miktar boş alan bırakacaktır, kısmen de bu bloğa başka bir tüm satırı sığdırmak mümkün olmayabilir (örneğin, bir 8K blok yalnızca 2 satıra sığacaktır) 3K, ancak 3K çoğu satır boyutundan çok daha büyük olduğu için bu uç bir örnek olacaktır). Dolayısıyla, BLOCKS (USER_TABLES içinde) daha iyi bir rehber olabilir.

Ancak bir tabloda 200.000 satırınız varsa, bunların yarısını sildiyseniz, o zaman tablo yine de aynı sayıda bloğa 'sahip olur'. Diğer masaların kullanması için onları serbest bırakmaz. Ayrıca, bloklar bir tabloya ayrı ayrı değil, 'kapsam' adı verilen gruplar halinde eklenir. Dolayısıyla bir tabloda genellikle EMPTY_BLOCKS (ayrıca USER_TABLES'te) olacaktır.


1

Bölümlenmiş tablolar için düzeltme:

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

Blok boyutuna göre tabloların ham boyutlarını döndüren basit seçim, ayrıca indeksli boyutu da içerir

table_name seçin, (nvl ((dba_indexes a'dan, dba_segments b'den toplamı (blokları) seçin, burada a.index_name = b.segment_name ve a.table_name = dba_tables.table_name), 0) + bloklar) * 8192/1024 Toplam Boyut, bloklar * 8 dba_tables'dan tableSize 3'e göre sırala


0

Bunu biraz daha doğru buldum:

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
Cevabıma biraz benziyor mu?
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

Birleştirmelerle "seçim" boyutunun ve seçenek olarak tablo boyutunun elde edilmesini sağlayan bir seçenek daha var

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

Tablo verilerinin, tablo dizinlerinin ve blob alanlarının segmentlerini hesaplayan sonlarla aynı varyanta sahibim:

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;

Kaynak .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.