<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>neilkodner.com &#187; open source</title>
	<atom:link href="http://www.neilkodner.com/tag/open-source/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.neilkodner.com</link>
	<description>Data Driven.  Since 1971.</description>
	<lastBuildDate>Sun, 23 Oct 2011 16:40:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Manager: How big is my table?  Me: What do you mean?</title>
		<link>http://www.neilkodner.com/2009/11/manager-how-big-is-my-table-me-what-do-you-mean/</link>
		<comments>http://www.neilkodner.com/2009/11/manager-how-big-is-my-table-me-what-do-you-mean/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 20:33:03 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[dba]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[plsql]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.neilkodner.com/?p=3</guid>
		<description><![CDATA[Recently, a data warehouse manager sent me a list of 49 tables; he wants the approximate size of each. For an end-user, this is no easy task. Sure, GUI interfaces such as Toad or OEM will give this information, but not all managers (or developers for that matter) know how to get this information. Furthermore, [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, a data warehouse manager sent me a list of 49 tables; he wants the approximate size of each.  For an end-user, this is no easy task.  Sure, GUI interfaces such as Toad or OEM will give this information, but not all managers (or developers for that matter) know how to get this information. </p>
<p>Furthermore, what constitutes table size?  Is it the space occupied by data?  What about indexes?  LOBs?  Oracle Text Indexes? Fortunately this schema didn&#8217;t contain any LOBs otherwise I&#8217;d have to look those sizes up.</p>
<p>Knowing what I do about both the manager and the project, I&#8217;m assuming that they wanted size info on these tables, to make sure we have enough room to clone them somewhere.  I chose the safest route and opted to produce data + index size for him. </p>
<p>My goal was to write a query that would present the data in a manager-friendly way.  A secondary goal(Sounds like I&#8217;ve been playing too much Command &#038; Conquer) would be to provide him with a query so he could get this information on his own.</p>
<p>Here&#8217;s my first cut at the query(explanation follows the SQL):</p>
<pre class="brush: sql; title: ; notranslate">with table_list as (select  table_name
                         ,  owner
                         ,  num_rows
                         ,  avg_row_len
                         ,  last_analyzed
            from  all_tables
           where  owner = 'SCHEMANAME'
             and  table_name in ( 'TABLE1'
                                , 'TABLE2'
                                , 'TABLE3'
...
                                , 'TABLE49'))
select  a.owner &quot;table owner&quot;
     ,  a.table_name &quot;table name&quot;
     ,  avg(ROUND(b.bytes/1024/1024,2)) &quot;table size in mb&quot;
     ,  avg(ROUND(b.bytes/1024/1024/1024,2)) &quot;table size in gb&quot;
     ,  COUNT(DISTINCT c.index_name) &quot;number of indexes&quot;
     ,  SUM(ROUND(d.bytes/1024/1024,2)) &quot;index size in mb&quot;
     ,  SUM(ROUND(d.bytes/1024/1024/1024 , 2)) &quot;index size in gb&quot;
     ,  ROUND((avg(b.bytes) + sum(d.bytes))/1024/1024,2) &quot;table + indexes in mb&quot;
     ,  ROUND((avg(b.bytes) + sum(d.bytes))/1024/1024/1024,2) &quot;table + indexes in gb&quot;
     ,  a.num_rows &quot;number of rows&quot;
     ,  a.avg_row_len &quot;average row length&quot;
     ,  a.last_analyzed &quot;last analyzed&quot;
  from  table_list a
     ,  dba_segments b
     ,  all_indexes c
     ,  dba_segments d
 where  a.table_name = b.segment_name
   and  b.segment_type = 'TABLE'
   and  a.owner = b.owner
   and  a.owner = c.owner(+)
   and  c.table_name(+) = a.table_name
   and  c.index_name = d.segment_name(+)
   and  c.owner = d.owner(+)
   and  d.segment_type(+) = 'INDEX'
GROUP BY  a.owner
       ,  a.table_name
       ,  a.num_rows
       ,  a.avg_row_len
       ,  a.last_analyzed
order by a.table_name</pre>
<p>I chose to put the hard-coded schema name and table list in a WITH query only to keep it at the top of the statement &#8211; so that the manager, or anyone else editing this query, could easily see where the editable items are.  </p>
<p>The results look like<br />
<img src="http://www.neilkodner.com/images/skitch/table_sizes-20091103-152323.jpg" alt="table size query results" /></p>
<p>So we&#8217;re off to a good start.  But then I wanted to make the process even more user-friendly.  That&#8217;s where the idea of putting this into a stored procedure came in to play.  I created a pipelined row function which displays all of the table + index information, now with LOB support.</p>
<p>So instead of running the query above, it&#8217;s just a matter of executing a function call(for each table):</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; select * From table(table_info_pkg.table_info('CLAIMS'));

TABLE_OWNER                      TABLE_NAME
-------------------------------- --------------------------------
TOTAL_TABLE_SIZE_IN_MB TOTAL_TABLE_SIZE_IN_GB TABLE_DATA_SIZE_IN_MB
---------------------- ---------------------- ---------------------
TABLE_DATA_SIZE_IN_GB NUMBER_OF_INDEXES INDEX_SIZE_IN_MB INDEX_SIZE_IN_GB
--------------------- ----------------- ---------------- ----------------
LOB_SIZE_IN_MB LOB_SIZE_IN_GB NUMBER_OF_LOBS LOBINDEX_SIZE_IN_MB
-------------- -------------- -------------- -------------------
LOBINDEX_SIZE_IN_GB  ROW_COUNT AVERAGE_ROW_LENGTH LAST_ANAL
------------------- ---------- ------------------ ---------
CUBS_OWNER                       CLAIMS
                     0                                          108
                  .11                14               89              .09

TABLE_OWNER                      TABLE_NAME
-------------------------------- --------------------------------
TOTAL_TABLE_SIZE_IN_MB TOTAL_TABLE_SIZE_IN_GB TABLE_DATA_SIZE_IN_MB
---------------------- ---------------------- ---------------------
TABLE_DATA_SIZE_IN_GB NUMBER_OF_INDEXES INDEX_SIZE_IN_MB INDEX_SIZE_IN_GB
--------------------- ----------------- ---------------- ----------------
LOB_SIZE_IN_MB LOB_SIZE_IN_GB NUMBER_OF_LOBS LOBINDEX_SIZE_IN_MB
-------------- -------------- -------------- -------------------
LOBINDEX_SIZE_IN_GB  ROW_COUNT AVERAGE_ROW_LENGTH LAST_ANAL
------------------- ---------- ------------------ ---------
             0              0              0                   0
                  0     379029                257 01-JUN-09
</pre>
<p>The code for table_info_pkg can be found <a href="http://code.google.com/p/table-info-pkg/">on google code</a> and I welcome any and all feedback, complaints, or anything else you care to throw at me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.neilkodner.com/2009/11/manager-how-big-is-my-table-me-what-do-you-mean/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

