Będąc przyzwyczajonym do MSSQL (i potencjalnie zepsutym przez), zastanawiam się, jak uzyskać rozmiar tabel w Oracle 10g. Przeszukałem go w Google, więc teraz jestem świadomy, że mogę nie mieć tak łatwej opcji jak sp_spaceused. Jednak potencjalne odpowiedzi, które otrzymałem, są w większości nieaktualne lub nie działają. Prawdopodobnie dlatego, że nie jestem DBA w schemacie, z którym pracuję.
Czy ktoś miałby rozwiązania i / lub zalecenia?
Odpowiedzi:
Możesz być zainteresowany tym zapytaniem. Informuje, ile miejsca jest przydzielone dla każdej tabeli, biorąc pod uwagę indeksy i wszelkie LOB w tabeli. Często interesuje Cię „Ile miejsca zajmuje tabela zamówień zakupu, w tym wszelkie indeksy”, a nie tylko sama tabela. Zawsze możesz zagłębić się w szczegóły. Należy pamiętać, że wymaga to dostępu do widoków 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 ;
źródło
-- 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. ;
źródło
null
(num_rows
,avg_row_len
), musisz wcześniej dokonać analizy za pomocą następującego oświadczeniaANALYZE TABLE your_table COMPUTE STATISTICS
Po pierwsze, generalnie ostrzegam, że zbieranie statystyk tabeli w celu przeprowadzenia analizy przestrzeni jest potencjalnie niebezpieczną rzeczą. Gromadzenie statystyk może zmienić plany zapytań, szczególnie jeśli administrator skonfigurował zadanie gromadzenia statystyk, które używa parametrów innych niż domyślne, których nie używa Twoje wywołanie, i spowoduje, że Oracle ponownie przeanalizuje zapytania wykorzystujące daną tabelę, co może być wydajnością trafienie. Jeśli DBA celowo pozostawił niektóre tabele bez statystyk (często w przypadku
OPTIMIZER_MODE
WYBIERZ), gromadzenie statystyk może spowodować, że Oracle przestanie używać optymalizatora regułowego i zacznie używać optymalizatora kosztowego dla zestawu zapytań, które mogą być bardzo wydajne ból głowy, jeśli dzieje się to nieoczekiwanie w produkcji. Jeśli twoje statystyki są dokładne, możesz zapytaćUSER_TABLES
(lubALL_TABLES
lubDBA_TABLES
) bezpośrednio bez dzwonieniaGATHER_TABLE_STATS
. Jeśli twoje statystyki nie są dokładne, prawdopodobnie jest ku temu powód i nie chcesz naruszać status quo.Po drugie, najbliższym odpowiednikiem
sp_spaceused
procedury SQL Server jest prawdopodobnieDBMS_SPACE
pakiet Oracle . Tom Kyte ma przyjemnąshow_space
procedurę, która zapewnia prosty interfejs do tego pakietu i wypisuje informacje podobne do tych, które sąsp_spaceused
drukowane.źródło
Najpierw zbierz statystyki optymalizatora na stole (jeśli jeszcze tego nie zrobiłeś):
begin dbms_stats.gather_table_stats('MYSCHEMA','MYTABLE'); end; /
OSTRZEŻENIE: Jak mówi Justin w swojej odpowiedzi, zbieranie statystyk optymalizatora wpływa na optymalizację zapytań i nie powinno być wykonywane bez należytej uwagi i rozwagi !
Następnie znajdź liczbę bloków zajmowanych przez stół z wygenerowanych statystyk:
select blocks, empty_blocks, num_freelist_blocks from all_tables where owner = 'MYSCHEMA' and table_name = 'MYTABLE';
Całkowita liczba bloków przydzielonych do tabeli to bloki + empty_blocks + num_freelist_blocks.
bloki to liczba bloków, które faktycznie zawierają dane.
Pomnóż liczbę bloków przez rozmiar używanego bloku (zwykle 8 KB), aby uzyskać zajęte miejsce - np. 17 bloków x 8 KB = 136 KB.
Aby zrobić to jednocześnie dla wszystkich tabel w schemacie:
begin dbms_stats.gather_schema_stats ('MYSCHEMA'); end; / select table_name, blocks, empty_blocks, num_freelist_blocks from user_tables;
Uwaga: zmiany wprowadzone w powyższym po przeczytaniu tego wątku AskTom
źródło
Zmodyfikowałem zapytanie WW, aby podać bardziej szczegółowe informacje:
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 /
źródło
W przypadku tabel i indeksów podzielonych na partycje możemy użyć następującego zapytania
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 ;
źródło
IIRC potrzebne tabele to DBA_TABLES, DBA_EXTENTS lub DBA_SEGMENTS i DBA_DATA_FILES. Istnieją również wersje USER_ i ALL_ tych tabel, które możesz sprawdzić, jeśli nie masz uprawnień administracyjnych na komputerze.
źródło
Oto wariant odpowiedzi WWs, zawiera partycje i pod-partycje, jak sugerowali inni powyżej, oraz kolumnę pokazującą TYP: Tabela / Indeks / LOB itp.
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;
źródło
select segment_name,segment_type,bytes/1024/1024 MB from dba_segments where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;
źródło
Zmodyfikowałem zapytanie, aby uzyskać rozmiar schematu na przestrzeń tabel.
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 ;
źródło
Zależy, co rozumiesz przez „rozmiar stołu”. Tabela nie odnosi się do konkretnego pliku w systemie plików. Tabela będzie znajdować się w obszarze tabel (prawdopodobnie w wielu obszarach tabel, jeśli jest podzielona na partycje, i prawdopodobnie w wielu obszarach tabel, jeśli chcesz również uwzględnić indeksy w tabeli). Obszar tabel często zawiera wiele tabel i może być rozłożony na wiele plików.
Jeśli szacujesz, ile miejsca będziesz potrzebować do przyszłego wzrostu tabeli, dobrym przewodnikiem będzie avg_row_len pomnożone przez liczbę wierszy w tabeli (lub liczbę wierszy, których oczekujesz w tabeli). Jednak Oracle pozostawi trochę wolnego miejsca na każdym bloku, częściowo po to, aby wiersze mogły „rosnąć”, jeśli zostaną zaktualizowane, częściowo dlatego, że może nie być możliwe zmieszczenie innego całego wiersza w tym bloku (np. Blok 8K zmieściłby się tylko w 2 wierszach 3K, chociaż byłby to skrajny przykład, ponieważ 3K jest dużo większe niż większość rozmiarów wierszy). Więc BLOCKS (w USER_TABLES) mogą być lepszym przewodnikiem.
Ale gdybyś miał 200 000 wierszy w tabeli i usunął połowę z nich, to tabela nadal „posiadała” taką samą liczbę bloków. Nie zwalnia ich do użycia w innych stołach. Ponadto bloki nie są dodawane do tabeli indywidualnie, ale w grupach zwanych „zakresem”. Więc generalnie w tabeli będzie EMPTY_BLOCKS (także w USER_TABLES).
źródło
Poprawka dla podzielonych tabel:
źródło
Prosty wybór, który zwraca surowe rozmiary tabel na podstawie rozmiaru bloku, obejmuje również rozmiar z indeksem
select table_name, (nvl ((select sum (bloki) from dba_indexes a, dba_segments b where a.index_name = b.segment_name and a.table_name = dba_tables.table_name), 0) + blocks) * 8192/1024 TotalSize, blocks * 8 tableSize z kolejności dba_tables o 3
źródło
Uważam, że jest to trochę dokładniejsze:
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
źródło
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 ;
źródło
jest jeszcze jedna opcja, która pozwala uzyskać "wybierz" rozmiar z łączeniami, a także rozmiar tabeli jako opcję
-- 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);
źródło
Mam ten sam wariant co ostatni, który oblicza segmenty danych tabeli, indeksy tabeli i pola 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;
Źródło .
źródło