ฉันจะคำนวณขนาดตารางใน Oracle ได้อย่างไร


128

เมื่อใช้ (และอาจถูกทำลายโดย) MSSQL ฉันสงสัยว่าฉันจะได้ขนาดตารางใน Oracle 10g ได้อย่างไร ฉันได้ googled แล้วตอนนี้ฉันรู้ว่าฉันอาจไม่มีตัวเลือกที่ง่ายเหมือน sp_spaceused คำตอบที่เป็นไปได้ที่ฉันได้รับส่วนใหญ่ล้าสมัยหรือไม่ได้ผล อาจเป็นเพราะฉันไม่ใช่ DBA ในสคีมาที่ฉันทำงานด้วย

ใครมีวิธีแก้ปัญหาและหรือคำแนะนำ


หากมี proc ให้คำตอบถูกทำให้เสียให้นำคำตอบที่คุณได้รับจากที่นี่มารวมเป็นขั้นตอนแล้วเรียกว่า ... dun dun duh ... sp_spaceused มีเวทมนตร์เล็กน้อยจริงๆ

1
@MarkBrady อาจจะไม่วิเศษ แต่ตันของความรู้ที่เป็นความลับเป็นสิ่งจำเป็น
jpmc26

คำตอบ:


201

คุณอาจสนใจคำถามนี้ จะบอกให้คุณทราบว่าแต่ละโต๊ะมีการจัดสรรพื้นที่เท่าใดโดยคำนึงถึงดัชนีและ LOB ใด ๆ บนโต๊ะ บ่อยครั้งที่คุณสนใจที่จะทราบว่า "ตารางใบสั่งซื้อใช้ช่องว่างเท่าใดรวมทั้งดัชนีใด ๆ " แทนที่จะเป็นเพียงตารางเท่านั้น คุณสามารถเจาะลึกรายละเอียดได้ตลอดเวลา โปรดทราบว่าสิ่งนี้ต้องการการเข้าถึงมุมมอง 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
;

1
โปรดทราบว่าคำตอบนี้จะนับส่วนต่างๆซึ่งไม่ได้แยกความแตกต่างระหว่างช่องว่างที่กำลังใช้งานกับช่องว่างที่ใช้ก่อนหน้านี้ เห็นได้ชัดว่าครั้งหนึ่งเคยเป็นส่วนที่ได้รับมอบหมายในตารางก็มักจะได้รับมอบหมายให้ตารางแม้ว่าพื้นที่ที่เป็นอิสระ ดูที่นี่ . ผมคิดว่าคุณต้องไปลงไปถึงระดับขอบเขตเพื่อดูว่าพื้นที่มากเป็นจริงใช้ ?
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.
;

หมายเหตุ: เป็นค่าประมาณซึ่งทำให้แม่นยำยิ่งขึ้นด้วยการรวบรวมสถิติ:

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

2
สถิติเหล่านี้อาจเป็นnull( num_rows, avg_row_len) คุณต้องทำการวิเคราะห์ก่อนผ่านข้อความต่อไปนี้ANALYZE TABLE your_table COMPUTE STATISTICS
Brice

การวิเคราะห์อย่างยากลำบากอาจใช้เวลานานมาก!
Brice

การทำงานที่ดีเมื่อฉันไม่สามารถตรวจสอบตารางที่ไม่มีตาราง
tungns304

30

ก่อนอื่นฉันมักจะเตือนว่าการรวบรวมสถิติตารางเพื่อทำการวิเคราะห์พื้นที่เป็นสิ่งที่อาจเป็นอันตรายได้ การรวบรวมสถิติอาจเปลี่ยนแผนการสืบค้นโดยเฉพาะอย่างยิ่งถ้า DBA ได้กำหนดค่างานการรวบรวมสถิติที่ใช้พารามิเตอร์ที่ไม่ใช่ค่าเริ่มต้นที่การโทรของคุณไม่ได้ใช้และจะทำให้ Oracle แยกวิเคราะห์คำค้นหาอีกครั้งที่ใช้ตารางที่เป็นปัญหาซึ่งอาจเป็นประสิทธิภาพ ตี. หาก DBA จงใจทิ้งตารางบางตารางโดยไม่มีสถิติ (โดยทั่วไปหากคุณOPTIMIZER_MODEเป็น CHOOSE) การรวบรวมสถิติอาจทำให้ Oracle หยุดใช้เครื่องมือเพิ่มประสิทธิภาพตามกฎและเริ่มใช้เครื่องมือเพิ่มประสิทธิภาพตามต้นทุนสำหรับชุดข้อความค้นหาซึ่งอาจเป็นประสิทธิภาพที่สำคัญ ปวดหัวถ้าทำโดยไม่คาดคิดในการผลิต หากสถิติของคุณถูกต้องคุณสามารถสอบถามUSER_TABLES(หรือALL_TABLESหรือDBA_TABLES) GATHER_TABLE_STATSได้โดยตรงโดยไม่ต้องโทร หากสถิติของคุณไม่ถูกต้องอาจเป็นเพราะสาเหตุนั้นและคุณไม่ต้องการรบกวนสภาพที่เป็นอยู่

ประการที่สองสิ่งที่ใกล้เคียงที่สุดกับsp_spaceusedขั้นตอนSQL Server น่าจะเป็นDBMS_SPACEแพ็คเกจของ Oracle Tom Kyte มีshow_spaceขั้นตอนที่ดีที่ให้อินเทอร์เฟซที่เรียบง่ายสำหรับแพ็คเกจนี้และพิมพ์ข้อมูลที่คล้ายกับสิ่งที่sp_spaceusedพิมพ์ออกมา


8

ขั้นแรกรวบรวมสถิติผู้เพิ่มประสิทธิภาพในตาราง (หากคุณยังไม่ได้ทำ):

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

คำเตือน: ดังที่จัสตินกล่าวไว้ในคำตอบของเขาการรวบรวมสถิติผู้เพิ่มประสิทธิภาพจะส่งผลต่อการเพิ่มประสิทธิภาพการสืบค้นและไม่ควรทำโดยปราศจากความระมัดระวังและการพิจารณา !

จากนั้นค้นหาจำนวนบล็อกที่ตารางครอบครองจากสถิติที่สร้างขึ้น:

select blocks, empty_blocks, num_freelist_blocks
from   all_tables
where  owner = 'MYSCHEMA'
and    table_name = 'MYTABLE';
  • จำนวนบล็อกทั้งหมดที่จัดสรรให้กับตารางคือบล็อก + empty_blocks + num_freelist_blocks

  • บล็อกคือจำนวนบล็อกที่มีข้อมูลอยู่จริง

คูณจำนวนบล็อกตามขนาดบล็อกที่ใช้งาน (โดยปกติคือ 8KB) เพื่อให้ได้พื้นที่ที่ใช้ไป - เช่น 17 บล็อก x 8KB = 136KB

ในการดำเนินการนี้กับทุกตารางในสคีมาพร้อมกัน:

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

select table_name, blocks, empty_blocks, num_freelist_blocks
from   user_tables;

หมายเหตุ: การเปลี่ยนแปลงข้างต้นหลังจากอ่านเธรด AskTom นี้


7

ฉันแก้ไขแบบสอบถามของ WW เพื่อให้ข้อมูลโดยละเอียดเพิ่มเติม:

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

สำหรับตารางและดัชนีที่แบ่งพาร์ติชันย่อยเราสามารถใช้แบบสอบถามต่อไปนี้



    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 ตารางที่คุณต้องการคือ DBA_TABLES, DBA_EXTENTS หรือ DBA_SEGMENTS และ DBA_DATA_FILES นอกจากนี้ยังมี USER_ และ ALL_ เวอร์ชันเหล่านี้สำหรับตารางที่คุณสามารถดูได้ว่าคุณไม่มีสิทธิ์การดูแลระบบบนเครื่องหรือไม่


4

นี่เป็นตัวแปรในคำตอบของ WW ซึ่งรวมถึงพาร์ติชันและพาร์ติชันย่อยตามที่คนอื่น ๆ แนะนำรวมทั้งคอลัมน์เพื่อแสดง TYPE: Table / Index / LOB เป็นต้น

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;


2

ฉันแก้ไขการสืบค้นเพื่อรับขนาดสคีมาต่อหนึ่งตาราง

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

ขึ้นอยู่กับความหมายของ "ขนาดโต๊ะ" ตารางไม่เกี่ยวข้องกับไฟล์เฉพาะบนระบบไฟล์ ตารางจะอยู่บนพื้นที่ตาราง (อาจมีหลายตารางถ้ามีการแบ่งพาร์ติชันและอาจมีหลายตารางตารางหากคุณต้องการพิจารณาดัชนีบนโต๊ะด้วย) ตารางตารางมักจะมีหลายตารางอยู่ในนั้นและอาจกระจายไปในหลายไฟล์

หากคุณกำลังประมาณว่าจะต้องใช้พื้นที่เท่าใดสำหรับการเติบโตในอนาคตของตาราง avg_row_len คูณด้วยจำนวนแถวในตาราง (หรือจำนวนแถวที่คุณคาดหวังในตาราง) จะเป็นแนวทางที่ดี แต่ Oracle จะปล่อยให้มีพื้นที่ว่างในแต่ละบล็อกส่วนหนึ่งเพื่อให้แถว 'เติบโต' หากมีการอัปเดตส่วนหนึ่งเป็นเพราะอาจไม่สามารถใส่แถวอื่นทั้งหมดในบล็อกนั้นได้ (เช่นบล็อก 8K จะพอดีกับ 2 แถวเท่านั้น ของ 3K แม้ว่าจะเป็นตัวอย่างที่รุนแรงเนื่องจาก 3K นั้นใหญ่กว่าขนาดแถวส่วนใหญ่มาก) ดังนั้น BLOCKS (ใน USER_TABLES) อาจเป็นแนวทางที่ดีกว่า

แต่ถ้าคุณมี 200,000 แถวในตารางให้ลบครึ่งหนึ่งจากนั้นตารางจะยังคง 'เป็นเจ้าของ' จำนวนบล็อกเท่าเดิม จะไม่ปล่อยให้ตารางอื่นใช้ นอกจากนี้บล็อกจะไม่ถูกเพิ่มลงในตารางทีละรายการ แต่ในกลุ่มเรียกว่า 'ขอบเขต' ดังนั้นโดยทั่วไปจะมี EMPTY_BLOCKS (เช่น USER_TABLES) ในตาราง


1

การแก้ไขตารางที่แบ่งพาร์ติชัน:

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

Simple select ที่ส่งคืนขนาดดิบของตารางตามขนาดบล็อกรวมถึงขนาดพร้อมดัชนีด้วย

เลือก table_name, (nvl ((เลือก sum (บล็อก) จาก dba_indexes a, dba_se segment b โดยที่ a.index_name = b.segment_name และ a.table_name = dba_tables.table_name), 0) + บล็อก) * 8192/1024 TotalSize บล็อก * 8 tableSize จาก dba_tables เรียงลำดับ 3


0

ฉันพบว่าสิ่งนี้แม่นยำกว่าเล็กน้อย:

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
ดูเหมือนคำตอบของฉัน?
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

มีอีกหนึ่งตัวเลือกที่อนุญาตให้รับขนาด "เลือก" พร้อมการรวมและขนาดตารางเป็นตัวเลือกด้วย

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

ฉันมีตัวแปรเดียวกับตัวสุดท้ายที่คำนวณส่วนของข้อมูลตารางดัชนีตารางและฟิลด์หยด:

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;

แหล่ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.