home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / database / oracle / 1274 < prev    next >
Encoding:
Internet Message Format  |  1992-08-12  |  17.6 KB

  1. Path: sparky!uunet!dtix!darwin.sura.net!seismo!jean
  2. From: jean@seismo.CSS.GOV (Jean Anderson)
  3. Newsgroups: comp.databases.oracle
  4. Subject: space management
  5. Message-ID: <51074@seismo.CSS.GOV>
  6. Date: 13 Aug 92 04:39:42 GMT
  7. Sender: usenet@seismo.CSS.GOV
  8. Organization: SAIC Open Systems Division, San Diego CA
  9. Lines: 507
  10. Nntp-Posting-Host: beno.css.gov
  11.  
  12. Somebody requested the script that generates a report I mentioned in a recent
  13. post:
  14.  
  15. >We routinely run 'actual vs. allocated' reports to see where we can recover
  16. >deleted space. We 'exp compress=y', 'imp indexfile=create.sql', and alter
  17. >the initial storage downward in the create script to a more reasonable 
  18. >allocation.
  19. >
  20. >A snippet from last night's report shows massive deletion in one of the tables:
  21.  
  22.                                        Blocks      Bytes        Bytes  Pct % of
  23. Segment Name                Rows  Ext   Alloc      Alloc         Used Used Data
  24. --------------------- ---------- ---- ------- ---------- ------------ ---- ----
  25. ARCHORID        DATA           2    4      30      61440        2,048    3     
  26.   ARCHORDX      INDEX               2      10      16826        5,680   34  277
  27.  
  28. KAUDIT          DATA     273,885   49    6092   12476416   12,288,000   98     
  29.   DOBJIDX       INDEX               5    4493    7678068    4,903,528   64   40
  30.  
  31. WFDISC          DATA       2,874   13    3391    6944768      464,896    7
  32.  
  33.  
  34. I added to the original snippet from the reports that ran this week. :-)
  35. I look for:
  36.  
  37.     o  Low "Pct Used"
  38.        WFDISC will be recreated smaller to free up wasted space.
  39.     o  High "Ext"ents
  40.        KAUDIT will be recreated larger to reduce fragmentation.
  41.     o  Peculiar "% of data"
  42.        This compares size of the index to size of the base data.  ARCHORID is 
  43.        too small to bother about, but I occasionally see indexes that are 2-3 
  44.        times the size of the base table. Dropping and recreating the index 
  45.        reduces it to a normal 10-20% of the base data (average for our 
  46.        datasets).
  47.  
  48. The scripts that generate this report are down below and are:
  49.  
  50. dba_actsize:     The main work horse stuffs info into a temp table.
  51. dba_actsize_rpt: Invoked by dba_actsize, this generates a report from the temp 
  52.                  table.  It is a separate sql*plus script because it is dense.
  53.                  I wanted to leave a hook for other "prettier" reports.
  54. Sample usage:
  55.  
  56.     I normally set up cron to run one or two reports each night on the "top 
  57.     hogs".  Reports are run on each hog once a week. It takes about an hour
  58.     to run on a 200meg account (SUN 4/330).
  59.  
  60.     sqlplus -s dba/xxx @dba_actsize geodemo.out geodemo dba_actsize_rpt
  61.                 |           |          |           |         |
  62.                 |         script       |           |         +=> report script
  63.                 |                      |           +=> user name
  64.                 |                      +=> output file name
  65.                 +=> I set it up so a DBA must run it because it is a serious
  66.                     hog. You may want to change it so non-DBA users can run it.
  67.  
  68. I started with Maurice Manton's ACTUAL_SIZE.SQL script, added INDEX information.
  69. The script does PL/SQL updates, so my apologies, but this won't help you if
  70. you don't have pl/sql.
  71.  
  72. It's something of a muddle, full of quickie kludges and stupid tricks to get
  73. something up and running fast.  All suggestions for fixes are welcome! I'm
  74. going to redesign/rewrite it entirely in pl/sql which will make it much more 
  75. readable. 
  76.  
  77.     - jean
  78.  
  79. +-----------------------------------------------------------------------+
  80. | Jean Anderson, DBA                       email:  jean@seismo.css.gov  |
  81. | SAIC Open Systems Division, MS A2-F         or:  jean@esosun.css.gov  |
  82. | 10210 Campus Point Drive                 phone:  (619)458-2727        |
  83. | San Diego, CA  92121                       fax:  (619)458-4993        |
  84. +-----------------------------------------------------------------------+
  85. |                     std_disclaimer("mine");                           |
  86. +-----------------------------------------------------------------------+
  87.  
  88. -----------------------------< dba_actsize.sql >------------------------------
  89. rem FILE
  90. rem    dba_actsize.sql
  91. rem
  92. rem DESCRIPTION
  93. rem    ORACLE stores how much space has been allocated to objects in the
  94. rem    SYS.USER_SEGMENTS and SYS.DBA_SEGMENTS data dictionary views.
  95. rem    Actual usage, however, is not stored.
  96. rem
  97. rem    This script reports allocated and actual space used by tables and
  98. rem    indexes belonging to a given user.
  99. rem
  100. rem    It extracts a list of tables and indexes from sys.dba_segments and
  101. rem    generates a second SQL script, space_temp.sql, with the actual
  102. rem    commands necessary for calculating space.
  103. rem
  104. rem    This script is a hog. It must be run by an account with dba privileges
  105. rem    and care should be taken not to run it on a large account during
  106. rem    database prime time usage.
  107. rem
  108. rem USAGE
  109. rem    sqlplus -s dba/password @dba_actsize output_filename user_id report_name
  110. rem
  111. rem NOTES
  112. rem    This section describes how actual usage is calculated.
  113. rem
  114. rem    CALCULATING SPACE USED BY TABLES
  115. rem    --------------------------------
  116. rem    ORACLE tags each record with a unique rowid that contains the datafile,
  117. rem    the block number, and the rownumber:
  118. rem
  119. rem        SQL> select arid, time, rowid, substr(rowid,15,4) filedata,
  120. rem          2  substr(rowid,1,8) block, substr(rowid,10,4) rownumber
  121. rem          3  from arrival;
  122. rem
  123. rem             ARID            TIME ROWID              FILE BLOCK    ROWN
  124. rem         -------- --------------- ------------------ ---- -------- ----
  125. rem           448579   654362719.300 0000764D.0000.0004 0004 0000764D 0000
  126. rem           448581   654362727.500 0000764D.0001.0004 0004 0000764D 0001
  127. rem           448582   654362732.150 0000764D.0002.0004 0004 0000764D 0002
  128. rem                                  -------- ---- ----
  129. rem                                  block    row  file
  130. rem
  131. rem    To find out how much space a table actually uses, count the number of
  132. rem    unique blocks in that table's rowid.  Since a single table could span
  133. rem    multiple database files and the same block number could show up in
  134. rem    both files, count the number of distinct block/file combinations:
  135. rem
  136. rem        select count(distinct(substr(rowid,1,8)||substr(rowid,15,4)))
  137. rem        from <table>;
  138. rem
  139. rem    This query is lifted from the ORACLE 6 DBA Guide, Chapter 6, page 10.
  140. rem    Note this is imprecise; it tells how many blocks are occupied, but
  141. rem    it won't say how much of each block is occupied.  A given block may
  142. rem    have 1 row in it--and yet be counted as a full 2048 byte ORACLE block.
  143. rem
  144. rem    CALCULATING SPACE USED BY INDEXES
  145. rem    ---------------------------------
  146. rem    The VALIDATE INDEX command populates the INDEX_STATS table and contains:
  147. rem
  148. rem        BLOCKS:       the blocks allocated to the INDEX
  149. rem        BTREE_SPACE:  total bytes allocated to the btree
  150. rem        USED_SPACE:   total bytes actually used
  151. rem        PCT_USED:     % of the BTREE_SPACE used (USED_SPACE/BTREE_SPACE)
  152. rem
  153. rem    The % used figure in this report is based on USED_SPACE/BLOCKS.
  154. rem
  155. rem  BUGS
  156. rem    This report is exceptionally labor-intensive to change. Make changes at
  157. rem    your own risk. Debug it by setting 'echo', 'termout', and 'verify' on.
  158. rem
  159. rem    The V7 version will be written entirely in PL/SQL, making it straight 
  160. rem    forward to read and debug.
  161. rem
  162. rem  ACKNOWLEDGEMENTS
  163. rem    This bounces off a script and paper by Maurice C. Manton III titled
  164. rem     "Space, The Great Unknown", presented at the 1990 International Oracle 
  165. rem     User Group meetings.
  166. rem
  167. rem    Funding for the development of this implementation was provided by
  168. rem    DARPA.
  169. rem
  170. rem  AUTHOR
  171. rem     Jean T. Anderson, SAIC Open Systems Division, November 1991
  172. rem
  173. rem  modification history:
  174. rem
  175. rem    jta    11/05/91    Created -- works with V6.0.30.3.1.
  176. rem    jta    11/14/91    Made space_temp.sql filename unique.
  177. rem    jta    11/15/91    Made temp table and index name unique.
  178. rem    jta    01/13/92    Expanded temp table to include data from
  179. rem                INDEX_STATS view.
  180. rem    jta    03/23/92    Certified for rdbms V6.0.33.2.2.
  181. rem    jta    08/12/92    Certified for rdbms V7.0.9.3.1, but it sure
  182. rem                ain't the right way to do it for V7!
  183. rem  SEE ALSO
  184. rem    dba_space(1)
  185. rem    DBA Guide, Chapter 6
  186. rem    OLS bulletin board article 99751.686 "INDEX STATISTICS"
  187. rem
  188. rem  SccsID @(#)dba_actsize.sql    48.3 8/12/92
  189.  
  190. WHENEVER SQLERROR EXIT FAILURE
  191.  
  192. define    filename = &1
  193. define    user_id = &2
  194. define    report_name = &3
  195. define    dot="."
  196.  
  197. rem    SESSIONID, the user's auditing identifier, is used for creating unique 
  198. rem    names for the intermediate sql script, the results table, and the index.
  199.  
  200. column    uniq_id    new_value sid noprint
  201. column    spfile    new_value spoolfile noprint
  202. column    ttable    new_value space_temp noprint
  203. column    tindex    new_value space_index noprint
  204. column    tmesg    new_value plmesg noprint
  205.  
  206. rem    Some Oracle installations have pause set for interactive work
  207. set    pause off
  208.  
  209. rem    Because of the "noprint", blank lines get output to stdout.
  210. rem    Suppress output of these blank lines with 'termout off'
  211. set    termout off
  212.  
  213. select    userenv('SESSIONID')    uniq_id
  214. from    dual
  215. /
  216.  
  217. select    &sid||'space_temp.sql'    spfile, 
  218.     'space_temp'||&sid    ttable,
  219.     'spacendx'||&sid    tindex,
  220.     'plmesg'||&sid        tmesg
  221. from    dual
  222. /
  223.  
  224. rem    The SQL code generated by this script must contain single quotes.
  225. rem    s_quote is a trick to surround character strings with single quotes in
  226. rem    space_temp.sql.  But s_quote itself has to be separated from the &,
  227. rem    otherwise it will get immediately expanded; hence the '&'||'s_quote.'
  228. rem    syntax in the queries below.
  229. define    s_quote = ''''
  230.  
  231. set    echo off
  232. set     verify off
  233. set     heading off
  234. set     pagesize 0
  235. set     feedback off
  236.  
  237. rem    -- Create the temp table.
  238. create    table &space_temp (
  239.     owner        varchar(30),
  240.     table_name    varchar(30),
  241.     segment_name    varchar(30),
  242.     segment_type    varchar(8),
  243.     recnum        number,
  244.     blocks_alloc    number,
  245.     bytes_alloc    number,
  246.     bytes_used    number,
  247.     pct_used    number,
  248.     pctind        number);
  249.  
  250. create    table &plmesg (seqno number(4), mesgtext varchar(255), lddate date);
  251.  
  252. spool    &spoolfile
  253.  
  254. rem    --- First generate SQL to perform TABLE calculations --
  255.  
  256. select    'insert into &'||'space_temp ',
  257.     '(owner,table_name,segment_name,segment_type,recnum,bytes_used)',
  258.     ' select ',
  259.     '&'||'s_quote.' || owner ||'&'||'s_quote, ',
  260.     '&'||'s_quote.' || segment_name ||'&'||'s_quote, ',
  261.     '&'||'s_quote.' || segment_name ||'&'||'s_quote, ',
  262.     '&'||'s_quote.TABLE&'||'s_quote, ',
  263.     'count(*), ',
  264.     'count(distinct(substr(rowid,1,8)||substr(rowid,15,4)))*2048 blocks',
  265.     ' from ', owner||'.'||segment_name, ';'
  266. from    sys.dba_segments
  267. where    segment_type = 'TABLE'
  268. and    owner=upper('&user_id');
  269.  
  270. rem    --- Now generate SQL to validate indexes ---
  271. rem    Later updates to fill in the table_name from sys.dba_indexes are 
  272. rem    remarkably expensive, so join in that information on the insert here.
  273. rem    However, to also fill in extents requires a third join to
  274. rem    sys.dba_segments--and that third join turns out to be costly.  Since
  275. rem    extents doesn't figure in any other calculations, sys.dba_segments 
  276. rem    will be joined in at the time the report is generated.
  277. rem
  278. rem    The rpad(';', 79, ' ') forces a line feed after the semicolon so the
  279. rem    validate index command will execute before the insert. Perhaps there
  280. rem    is a better way to force a linefeed?
  281.  
  282. select 'validate index ', owner||'.'||segment_name, rpad(';', 79, ' '),
  283.     'insert into &'||'space_temp ',
  284.     '(owner,table_name,segment_name,segment_type,blocks_alloc,bytes_alloc,bytes_used,pct_used)',
  285.     'select ',
  286.     'UPPER(&'||'s_quote.&user_id&'||'s_quote), ',
  287.     'd.table_name, i.name, ',
  288.     '&'||'s_quote.INDEX&'||'s_quote, ',
  289.     'i.blocks, i.btree_space, i.used_space, i.pct_used ',
  290.     'from sys.dba_indexes d, index_stats i ',
  291.     'where d.index_name=i.name and d.owner=',
  292.     'UPPER(&'||'s_quote.&user_id&'||'s_quote);'
  293. from    sys.dba_segments
  294. where    segment_type = 'INDEX'
  295. and    owner=UPPER('&user_id');
  296.  
  297. spool off
  298. /
  299.  
  300. rem    -- Run the script --
  301.  
  302. start &spoolfile
  303. host    rm -f &spoolfile
  304.  
  305. rem    -- Set an index for updating statistics in temp table
  306. rem    -- This will commit pending changes
  307.  
  308. create unique index &space_index on &space_temp (owner, segment_name) pctfree=0;
  309.  
  310. rem    -- Update TABLE information
  311. rem    Correlated UPDATES are notoriously slow (see Tech Bulletin #99590.164).
  312. rem    PL/SQL is a much faster way to do these updates, which now include: 
  313. rem       (1)    TABLE: get blocks_alloc from sys.dba_segments (INDEXES got 
  314. rem        it from the INDEX_STATS table). segments_cursor does this.
  315. rem       (2)  TABLE: Update bytes_alloc and pct_used (space_cursor).
  316. rem       (3)  INDEX: Update size of index/size of base data (space_cursor).
  317. rem
  318. set    termout on
  319. DECLARE
  320.         CURSOR  segments_cursor is
  321.             SELECT  d.owner, d.segment_name, d.segment_type, d.blocks
  322.             FROM    sys.dba_segments d
  323.             WHERE   d.owner=UPPER('&user_id')
  324.           AND    d.segment_type = 'TABLE';
  325.  
  326.         CURSOR  space_cursor IS
  327.                 SELECT  table_name, segment_type, blocks_alloc, bytes_alloc,
  328.             bytes_used, pct_used, pctind
  329.                 FROM    &space_temp
  330.                 ORDER   by table_name asc, segment_type desc
  331.                 FOR    UPDATE OF bytes_alloc, pct_used, pctind;
  332.  
  333.     segments_ptr    segments_cursor%ROWTYPE;
  334.     space_ptr    space_cursor%ROWTYPE;
  335.  
  336.         tbytes          &space_temp.&dot.bytes_used%TYPE;
  337.     msg        &plmesg.&dot.mesgtext%TYPE;
  338.     badcount    number:= 0;
  339. BEGIN
  340.  
  341.                 -- Update blocks allocated to tables. Owner is redundant in 
  342.         -- this query, but is included so the space_temp index is used.
  343.     OPEN segments_cursor;
  344.     LOOP
  345.         FETCH segments_cursor INTO segments_ptr;
  346.         EXIT WHEN segments_cursor%NOTFOUND;
  347.  
  348.                    UPDATE  &space_temp
  349.                    SET     blocks_alloc=segments_ptr.blocks
  350.                    WHERE   owner=segments_ptr.owner
  351.           AND    segment_name=segments_ptr.segment_name;
  352.  
  353.         END LOOP;
  354.     CLOSE    segments_cursor;
  355.         COMMIT;
  356.  
  357.         -- Update bytes_alloc and pct_used for TABLES.
  358.         -- Update pctind for INDEXES.
  359.  
  360.     OPEN    space_cursor;
  361.     LOOP
  362.         FETCH space_cursor INTO space_ptr;
  363.         EXIT WHEN space_cursor%NOTFOUND;
  364.  
  365.                 IF      space_ptr.segment_type = 'TABLE'
  366.                 THEN
  367.             UPDATE    &space_temp
  368.             SET    bytes_alloc=space_ptr.blocks_alloc*2048,
  369.                 pct_used=round(space_ptr.bytes_used/(space_ptr.blocks_alloc*2048)*100)
  370.             WHERE   CURRENT OF space_cursor;
  371.  
  372.             tbytes := space_ptr.bytes_used;
  373.                 ELSE
  374.             IF tbytes > 0
  375.             THEN
  376.                             UPDATE  &space_temp 
  377.                 SET    pctind = round(space_ptr.bytes_used/tbytes*100)
  378.                             WHERE   CURRENT OF space_cursor;
  379.             END IF;
  380.                 END IF;
  381.         END LOOP;
  382.     CLOSE    space_cursor;
  383.         COMMIT;
  384.  
  385. EXCEPTION
  386.     WHEN ZERO_DIVIDE THEN
  387.         badcount := badcount+1;
  388.         msg := 'Cannot divide by 0';
  389.         insert into &plmesg(seqno, mesgtext, lddate)
  390.         values (badcount, msg, sysdate);
  391.         commit;
  392.     WHEN OTHERS THEN
  393.         badcount := badcount+1;
  394.         msg := substr(SQLERRM, 1, 70);
  395.         insert into &plmesg(seqno, mesgtext, lddate)
  396.         values (badcount, msg, sysdate);
  397.         commit;
  398. END;
  399. /
  400.  
  401. rem   -- Output any errors from PL/SQL block
  402. column    seqno format 999 heading x NOPRINT
  403. column    mesgtext format A58 WORD_WRAPPED
  404. column    lddate format A18
  405. select    seqno, mesgtext, '  ', to_char(lddate,'DD-Mon-YY HH24:mi:ss') lddate
  406. from    &plmesg
  407. where    seqno > 0
  408. order    by 1;
  409.  
  410. set termout off
  411. rem    -- Output the space report. --
  412.  
  413. start &report_name &filename &space_temp
  414.  
  415. drop table &space_temp;
  416.  
  417. drop table &plmesg;
  418.  
  419. exit SUCCESS
  420. ---------------------------------< dba_actsize_rpt.sql >----------------------
  421. rem  FILE
  422. rem    dba_actsize_rpt.sql
  423. rem
  424. rem  DESCRIPTION
  425. rem    This outputs a report from the temporary table created by dba_actsize.
  426. rem
  427. rem  USAGE
  428. rem    (called by dba_actsize)
  429. rem
  430. rem    start dba_actsize_rpt filename table_name
  431. rem
  432. rem  AUTHOR
  433. rem    Jean Anderson, SAIC Open Systems Operation, November 1991
  434. rem
  435. rem SccsID =@(#)dba_actsize_rpt.sql    48.1 6/19/92
  436. define reportname="dba_actsize_rpt.sql (v48.1)"
  437.  
  438. define    filename = &1
  439. define    tablename = &2
  440.  
  441. rem    Some Oracle installations have pause set for interactive work
  442. set    pause off
  443.  
  444. rem    -- Output report. --
  445.  
  446. set    pagesize 62
  447. rem    newpage forces a formfeed
  448. set    newpage 0
  449. set    linesize 79
  450. set    heading on
  451. set    feedback off
  452.  
  453. column    segment_name    format A21 HEADING "Segment Name";
  454. column    recnum        format 9,999,990 HEADING "Rows"
  455. column    extents        format 990 HEADING "Ext";
  456.  
  457. rem    -- A table with 999,999 blocks would be 2 gigabytes, but 99999 blocks
  458. rem    -- would only allow for 200 meg, so go ahead and give it the extra.
  459. column    blocks_alloc    format 999990 HEADING "Blocks|Alloc";
  460. column    bytes_alloc    format 999999990 HEADING "Bytes|Alloc";
  461. column    bytes_used    format 999,999,990 HEADING "Bytes|Used";
  462. column    pct_used    format 990 HEADING "Pct|Used";
  463. column    pctind        format 990 HEADING "% of|Data"
  464.  
  465. rem    -- break_column is used to suppress the output of ***** and 'sum'
  466. column    break_column    noprint
  467. column    today new_value rpt_date noprint
  468. select    to_char(sysdate, 'dd-Mon-yy hh24:mi') today from dual;
  469.  
  470. rem    -- this for sorting
  471. column  sort_column noprint
  472.  
  473. break    on table_name on break_column skip 1 on report;
  474. compute sum of blocks_alloc on break_column;
  475. compute sum of blocks_alloc on report;
  476. compute sum of bytes_alloc on break_column;
  477. compute sum of bytes_alloc on report;
  478. compute sum of bytes_used on break_column;
  479. compute sum of bytes_used on report;
  480. compute sum of pctind on break_column;
  481.  
  482. ttitle  skip center "Space Utilization Report for User '&user_id' on &rpt_date" -
  483.     skip 2
  484. /
  485. btitle    skip left '&reportname' -
  486.     right 'Page' FORMAT 99 sql.pno
  487. /
  488.  
  489. rem    The decode statement below forces index names to be indented two
  490. rem    characters below the parent table name.
  491.  
  492. select    b.table_name    break_column,
  493.     b.segment_type    sort_column,
  494.     decode(b.segment_type,
  495.         'TABLE',
  496.         rpad(substr(b.segment_name,1,15),16)||'DATA',
  497.         'INDEX',
  498.         '  '||rpad(substr(b.segment_name,1,13),14)||'INDEX') 
  499.         segment_name,
  500.     b.recnum,
  501.     a.extents,
  502.     b.blocks_alloc,
  503.     b.bytes_alloc,
  504.     b.bytes_used,
  505.     b.pct_used,
  506.     b.pctind
  507. from    sys.dba_segments a, &tablename b
  508. where    a.segment_name=b.segment_name 
  509.   and    a.owner=b.owner
  510. order    by b.table_name asc, b.segment_type desc, b.segment_name asc
  511.  
  512. spool    &filename
  513. /
  514. spool off
  515. /
  516.  
  517. exit
  518. ---------------------------------< end post >----------------------------------
  519.