¿Cómo calculo el tamaño de las tablas en Oracle?

128

Al estar acostumbrado (y potencialmente estropeado) a MSSQL, me pregunto cómo puedo llegar al tamaño de las tablas en Oracle 10g. Lo busqué en Google, así que ahora sé que es posible que no tenga una opción tan fácil como sp_spaceused. Aún así, las posibles respuestas que obtuve están desactualizadas la mayoría de las veces o no funcionan. Probablemente porque no soy un DBA en el esquema con el que estoy trabajando.

¿Alguien tendría soluciones o recomendaciones?

Rollo Tomazzi
fuente
si tener un proceso que dé la respuesta se está echando a perder, entonces tome las respuestas que obtuvo de aquí y envuélvalas en un procedimiento y llámelo ... dun dun duh ... sp_spaceused. Realmente hay poca magia.
1
@ MarkBrady Tal vez no sea mágico, pero se requiere un montón de conocimiento arcano.
jpmc26

Respuestas:

201

Quizás te interese esta consulta. Le indica cuánto espacio se asigna para cada tabla teniendo en cuenta los índices y cualquier LOB en la tabla. A menudo le interesa saber "Cuántos espacios ocupa la tabla de órdenes de compra, incluidos los índices" en lugar de solo la tabla en sí. Siempre puedes profundizar en los detalles. Tenga en cuenta que esto requiere acceso a las vistas 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.
fuente
1
Tenga en cuenta que esta respuesta cuenta segmentos, que no distinguen entre el espacio que está actualmente en uso y el espacio que estaba en uso anteriormente. Aparentemente, una vez que un segmento se asigna a una tabla, siempre se asigna a una tabla, incluso si se libera el espacio. Ver aquí . Supongo que tienes que bajar al nivel de extensión para ver cuánto espacio se usa realmente .
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.
;

Nota: Estas son estimaciones, hechas más precisas con las estadísticas de recopilación:

exec dbms_utility.analyze_schema(user,'COMPUTE');
grokster
fuente
2
Estas estadísticas pueden ser null( num_rows, avg_row_len), debe realizar un análisis antes a través de la siguiente declaraciónANALYZE TABLE your_table COMPUTE STATISTICS
Brice
¡Analizarlos puede ser muy largo!
Brice
buen trabajo cuando no puedo verificar una tabla sin espacio de tabla
tungns304
30

En primer lugar, generalmente advertiría que recopilar estadísticas de la tabla para hacer análisis de espacio es algo potencialmente peligroso. La recopilación de estadísticas puede cambiar los planes de consulta, especialmente si el DBA ha configurado un trabajo de recopilación de estadísticas que utiliza parámetros no predeterminados que su llamada no está utilizando, y hará que Oracle vuelva a analizar las consultas que utilizan la tabla en cuestión, lo que puede ser un rendimiento golpear. Si el DBA ha dejado intencionalmente algunas tablas sin estadísticas (común si su OPTIMIZER_MODEESCOGER), la recopilación de estadísticas puede hacer que Oracle deje de usar el optimizador basado en reglas y comience a usar el optimizador basado en costos para un conjunto de consultas que pueden ser un rendimiento importante dolor de cabeza si se hace inesperadamente en producción. Si sus estadísticas son precisas, puede consultar USER_TABLES( ALL_TABLESoDBA_TABLES) directamente sin llamar GATHER_TABLE_STATS. Si sus estadísticas no son precisas, probablemente haya una razón para eso y no desee alterar el statu quo.

En segundo lugar, el equivalente más cercano al sp_spaceusedprocedimiento de SQL Server es probablemente el DBMS_SPACEpaquete de Oracle . Tom Kyte tiene un buen show_spaceprocedimiento que proporciona una interfaz simple para este paquete e imprime información similar a la que se sp_spaceusedimprime.

Justin Cave
fuente
8

Primero, reúna las estadísticas del optimizador en la mesa (si aún no lo ha hecho):

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

ADVERTENCIA: como dice Justin en su respuesta, la recopilación de estadísticas del optimizador afecta la optimización de consultas y no debe hacerse sin el debido cuidado y consideración .

Luego encuentre el número de bloques ocupados por la tabla de las estadísticas generadas:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • El número total de bloques asignados a la tabla es blocks + empty_blocks + num_freelist_blocks.

  • bloques es el número de bloques que realmente contienen datos.

Multiplique el número de bloques por el tamaño de bloque en uso (generalmente 8 KB) para obtener el espacio consumido, por ejemplo, 17 bloques x 8 KB = 136 KB.

Para hacer esto para todas las tablas de un esquema a la vez:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

Nota: Los cambios realizados en lo anterior después de leer este hilo de AskTom

Tony Andrews
fuente
7

Modifiqué la consulta de WW para proporcionar información más detallada:

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

Para tablas e índices subdivididos podemos usar la siguiente consulta



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

IIRC las tablas que necesita son DBA_TABLES, DBA_EXTENTS o DBA_SEGMENTS y ​​DBA_DATA_FILES. También hay versiones USER_ y ALL_ de estas para las tablas que puede ver si no tiene permisos de administración en la máquina.

Preocupado por TunbridgeWells
fuente
4

Heres una variante en la respuesta WWs, incluye particiones y subparticiones como otros han sugerido anteriormente, además de una columna para mostrar el TIPO: Tabla / Índice / 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;
SS64
fuente
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
fuente
2

Modifiqué la consulta para obtener el tamaño del esquema por espacio de tabla.

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

Depende de lo que quieras decir con "tamaño de la mesa". Una tabla no se relaciona con un archivo específico en el sistema de archivos. Una tabla residirá en un espacio de tabla (posiblemente múltiples espacios de tabla si está particionado, y posiblemente múltiples espacios de tabla si también desea tener en cuenta los índices en la tabla). Un espacio de tabla a menudo tendrá varias tablas y puede extenderse a través de múltiples archivos.

Si está calculando cuánto espacio necesitará para el crecimiento futuro de la tabla, entonces avg_row_len multiplicado por el número de filas en la tabla (o el número de filas que espera en la tabla) será una buena guía. Pero Oracle dejará algo de espacio libre en cada bloque, en parte para permitir que las filas 'crezcan' si se actualizan, en parte porque puede que no sea posible colocar otra fila completa en ese bloque (por ejemplo, un bloque de 8K solo cabría en 2 filas de 3K, aunque eso sería un ejemplo extremo ya que 3K es mucho más grande que la mayoría de los tamaños de fila). Entonces BLOQUES (en USER_TABLES) podría ser una mejor guía.

Pero si tuviera 200,000 filas en una tabla, eliminara la mitad de ellas, entonces la tabla todavía 'poseería' la misma cantidad de bloques. No los libera para que otras tablas los usen. Además, los bloques no se agregan a una tabla individualmente, sino en grupos llamados 'extensión'. Por lo tanto, generalmente habrá EMPTY_BLOCKS (también en USER_TABLES) en una tabla.

Gary Myers
fuente
1

Corrección para tablas particionadas:

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

La selección simple que devuelve los tamaños sin formato de las tablas, en función del tamaño del bloque, también incluye el tamaño con el índice

select table_name, (nvl ((select sum (blocks) 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 de dba_tables ordenado por 3

Noam
fuente
0

Encontré que esto es un poco más preciso:

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
fuente
77
¿Se parece un poco a mi respuesta?
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
fuente
-2

Hay una opción más que permite obtener el tamaño de "selección" con combinaciones, y el tamaño de la tabla como opción también

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

Tengo la misma variante que las últimas que calcula segmentos de datos de tabla, índices de tabla y campos de 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;

Fuente .

user2498491
fuente