Étant habitué (et potentiellement gâté par) MSSQL, je me demande comment je peux obtenir la taille des tables dans Oracle 10g. Je l'ai googlé, donc je suis maintenant conscient du fait que je n'ai peut-être pas une option aussi facile que sp_spaceused. Néanmoins, les réponses potentielles que j'ai obtenues sont la plupart du temps obsolètes ou ne fonctionnent pas. Probablement parce que je ne suis pas DBA sur le schéma avec lequel je travaille.
Quelqu'un aurait-il des solutions et/ou des recommandations?
Vous pourriez être intéressé par cette requête. Il vous indique combien d’espace est alloué pour chaque table en tenant compte des index et des objets LOB de la table. Vous êtes souvent intéressé par connaître "La quantité d'espace occupée par la table Commande d'achat, y compris tous les index" plutôt que par la table elle-même. Vous pouvez toujours plonger dans les détails. Notez que cela nécessite un accès aux vues 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
;
-- 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.
;
Remarque: Il s'agit d'estimations, rendues plus précises avec les statistiques de collecte:
exec dbms_utility.analyze_schema(user,'COMPUTE');
Tout d'abord, je tiens à souligner que la collecte de statistiques sous forme de tables afin d'analyser l'espace est une opération potentiellement dangereuse. La collecte de statistiques peut modifier les plans de requête, en particulier si l'administrateur de base de données a configuré un travail de collecte de statistiques utilisant des paramètres non définis par défaut que votre appel n'utilise pas, et obligera Oracle à ré-analyser les requêtes utilisant la table en question, ce qui peut être une performance. frappé. Si l'administrateur de base de données a volontairement laissé certaines tables sans statistiques (commun si votre _OPTIMIZER_MODE
_ est CHOOSE), la collecte de statistiques peut amener Oracle à cesser d'utiliser l'optimiseur basé sur des règles et à utiliser l'optimiseur basé sur les coûts pour un ensemble de requêtes qui peut être un casse-tête majeur de performance si cela se fait de manière inattendue en production. Si vos statistiques sont exactes, vous pouvez interroger _USER_TABLES
_ (ou _ALL_TABLES
_ ou _DBA_TABLES
_) directement sans appeler _GATHER_TABLE_STATS
_. Si vos statistiques ne sont pas exactes, il y a probablement une raison à cela et vous ne voulez pas perturber le statu quo.
Deuxièmement, l'équivalent le plus proche de la procédure SQL Server _sp_spaceused
_ est probablement le package _DBMS_SPACE
_ d'Oracle. Tom Kyte a une procédure Nice show_space
qui fournit une interface simple à ce paquetage et affiche des informations similaires à celles imprimées par _sp_spaceused
_.
Tout d’abord, rassemblez les statistiques de l’optimiseur sur la table (si ce n’est déjà fait):
begin
dbms_stats.gather_table_stats('MYSCHEMA','MYTABLE');
end;
/
AVERTISSEMENT: comme le dit Justin dans sa réponse, la collecte de statistiques d'optimisation affecte l'optimisation des requêtes et ne doit pas être effectuée sans précaution et considération !
Recherchez ensuite le nombre de blocs occupés par la table à partir des statistiques générées:
select blocks, empty_blocks, num_freelist_blocks
from all_tables
where owner = 'MYSCHEMA'
and table_name = 'MYTABLE';
Le nombre total de blocs alloués à la table est le suivant: blocs + empty_blocks + num_freelist_blocks.
blocs est le nombre de blocs contenant réellement des données.
Multipliez le nombre de blocs par la taille de bloc utilisée (généralement 8 Ko) pour obtenir l'espace utilisé - par ex. 17 blocs x 8 Ko = 136 Ko.
Pour faire cela pour toutes les tables d'un schéma à la fois:
begin
dbms_stats.gather_schema_stats ('MYSCHEMA');
end;
/
select table_name, blocks, empty_blocks, num_freelist_blocks
from user_tables;
Remarque: modifications apportées à ce qui suit après la lecture de ce fil de discussion AskTom
J'ai modifié la requête de WW pour fournir des informations plus détaillées:
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
/
Pour les index et les tables sous-partitionnées, nous pouvons utiliser la requête suivante
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
;
Les tables IIRC dont vous avez besoin sont DBA_TABLES, DBA_EXTENTS ou DBA_SEGMENTS et DBA_DATA_FILES. Il existe également des versions USER_ et ALL_ de celles-ci pour les tables que vous pouvez voir si vous ne disposez pas des autorisations d'administration sur la machine.
Voici une variante de la réponse WW, elle inclut des partitions et des sous-partitions comme suggéré par les précédents, plus une colonne pour afficher le 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;
select segment_name,segment_type,bytes/1024/1024 MB
from dba_segments
where segment_name='TABLENAME' and owner ='OWNERNAME' order by mb desc;
Correction pour les tables partitionnées:
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 ;
J'ai modifié la requête pour obtenir la taille du schéma par espace de table.
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
;
Cela dépend de ce que vous entendez par "taille de la table". Une table ne concerne pas un fichier spécifique du système de fichiers. Une table réside sur un espace de table (éventuellement plusieurs espaces de table si elle est partitionnée et éventuellement plusieurs espaces de table si vous souhaitez également prendre en compte les index de la table). Un tablespace contient souvent plusieurs tables et peut être réparti sur plusieurs fichiers.
Si vous estimez la quantité d'espace dont vous aurez besoin pour la croissance future de la table, avg_row_len, multiplié par le nombre de lignes de la table (ou le nombre de lignes attendu dans la table), constitue un bon indicateur. Mais Oracle laissera de l'espace libre sur chaque bloc, en partie pour permettre aux lignes de "grandir" si elles sont mises à jour, en partie parce qu'il pourrait ne pas être possible d'ajuster une autre ligne entière sur ce bloc (par exemple, un bloc de 8 Ko ne contiendrait que 2 lignes de 3K, bien que ce soit un exemple extrême car 3K est beaucoup plus grand que la plupart des tailles de rangées). BLOCKS (dans USER_TABLES) pourrait donc être un meilleur guide.
Mais si vous aviez 200 000 lignes dans une table et en supprimiez la moitié, la table "posséderait" toujours le même nombre de blocs. Cela ne les libère pas pour que d'autres tables puissent les utiliser. De plus, les blocs ne sont pas ajoutés à une table individuellement, mais par groupes appelés "étendue". Ainsi, il y aura généralement EMPTY_BLOCKS (également dans USER_TABLES) dans une table.
J'ai trouvé cela un peu plus précis:
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
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 ;
Une sélection simple qui renvoie les tailles brutes des tables, en fonction de la taille du bloc, inclut également la taille avec index
select table_name, (nvl ((select sum (blocks) from dba_indexes a, dba_segments b où a.index_name = b.segment_name et a.table_name = dba_tables.nom_table), 0) + blocs) * 8192/1024 TotalSize, blocs * 8 tableSize de dba_tables ordre par 3