If the C code for the prior dbsize patch is not acceptable for whatever 
reason, here's a SQL-based patch to replace it.  It's not a drop-in for 
7.3/7.4 as I'd hoped, only an 8.1 patch.  I believe it is functionally 
equivalent to the C patch, but simpler, shorter, and probably a tad slower.  
I also removed the README section on how to aggregate since it was 
incomplete/incorrect (it didn't count toasted indices) and added a SQL 
function that itemizes the size for a relation's table and index data 
(helpful to us in identifying bloat, measuring performance, capacity 
estimation, etc).

Ed
? contrib/dbsize/README.dbsize.aggregate_relation_components
? contrib/dbsize/dbsize.sql
? contrib/dbsize/dbsize.sql.in.aggregate_relation_components
? contrib/dbsize/dbsize.sql.in.using_pg_relation_size
Index: contrib/dbsize/README.dbsize
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/dbsize/README.dbsize,v
retrieving revision 1.4
diff -C1 -r1.4 README.dbsize
*** contrib/dbsize/README.dbsize	28 Sep 2004 19:35:43 -0000	1.4
--- contrib/dbsize/README.dbsize	28 Jan 2005 17:10:31 -0000
***************
*** 1,3 ****
! This module contains several functions that report the size of a given
! database object:
  
--- 1,3 ----
! This module contains several functions that report the on-disk size of a 
! given database object in bytes:
  
***************
*** 5,6 ****
--- 5,10 ----
  	int8 relation_size(text)
+ 	int8 indexes_size(text)
+ 	int8 aggregate_relation_size(text)
+ 
+ 	setof record relation_size_components(text)
  
***************
*** 12,14 ****
  
! The first two functions:
  
--- 16,20 ----
  
! The first four functions take the name of the object (possibly 
! schema-qualified for the latter three) and returns the size of the
! on-disk files in bytes.
  
***************
*** 16,20 ****
  	SELECT relation_size('pg_class');
  
! take the name of the object (possibly schema-qualified, for relation_size),
! while these functions take object OIDs:
  	
--- 22,32 ----
  	SELECT relation_size('pg_class');
+ 	SELECT indexes_size('pg_class');
+ 	SELECT aggregate_relation_size('pg_class');
+ 
+ The next function, relation_size_components(), returns a set of rows
+ showing the sizes of the relations constituting the input relation.
+ 
+     SELECT relation_size_components('pg_class');
  
! These functions take object OIDs:
  	
***************
*** 24,49 ****
  
  Please note that relation_size and pg_relation_size report only the size of
  the selected relation itself; any subsidiary indexes or toast tables are not
! counted.  To obtain the total size of a table including all helper files
! you'd have to do something like:
! 
! SELECT *,
!     pg_size_pretty(tablesize+indexsize+toastsize+toastindexsize) AS totalsize
! FROM
! (SELECT pg_relation_size(cl.oid) AS tablesize,
!         COALESCE((SELECT SUM(pg_relation_size(indexrelid))::bigint
!                   FROM pg_index WHERE cl.oid=indrelid), 0) AS indexsize,
!         CASE WHEN reltoastrelid=0 THEN 0
!              ELSE pg_relation_size(reltoastrelid)
!         END AS toastsize,
!         CASE WHEN reltoastrelid=0 THEN 0
!              ELSE pg_relation_size((SELECT reltoastidxid FROM pg_class ct
!                                     WHERE ct.oid = cl.reltoastrelid))
!         END AS toastindexsize
!  FROM pg_class cl
!  WHERE relname = 'foo') ss;
! 
! This sample query utilizes the helper function pg_size_pretty(int8),
! which formats the number of bytes into a convenient string using KB, MB,
! GB.  It is also contained in this module.
  
--- 36,47 ----
  
+ The indexes_size() function returns the total size of the indices for a 
+ relation, including any toasted indices.
+ 
+ The aggregate_relation_size() function returns the total size of the relation,
+ all its indices, and any toasted data.  
+ 
  Please note that relation_size and pg_relation_size report only the size of
  the selected relation itself; any subsidiary indexes or toast tables are not
! counted.  To obtain the total size of a table including all helper files,
! use aggregate_relation_size().
  
Index: contrib/dbsize/dbsize.sql.in
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/dbsize/dbsize.sql.in,v
retrieving revision 1.4
diff -C1 -r1.4 dbsize.sql.in
*** contrib/dbsize/dbsize.sql.in	28 Sep 2004 19:35:43 -0000	1.4
--- contrib/dbsize/dbsize.sql.in	28 Jan 2005 17:10:32 -0000
***************
*** 1,2 ****
! CREATE FUNCTION database_size (name) RETURNS bigint
      AS 'MODULE_PATHNAME', 'database_size'
--- 1,2 ----
! CREATE OR REPLACE FUNCTION database_size (name) RETURNS bigint
      AS 'MODULE_PATHNAME', 'database_size'
***************
*** 4,10 ****
  
! CREATE FUNCTION relation_size (text) RETURNS bigint
!     AS 'MODULE_PATHNAME', 'relation_size'
!     LANGUAGE C STRICT;
! 
! CREATE FUNCTION pg_tablespace_size(oid) RETURNS bigint
      AS 'MODULE_PATHNAME', 'pg_tablespace_size'
--- 4,6 ----
  
! CREATE OR REPLACE FUNCTION pg_tablespace_size(oid) RETURNS bigint
      AS 'MODULE_PATHNAME', 'pg_tablespace_size'
***************
*** 12,14 ****
  
! CREATE FUNCTION pg_database_size(oid) RETURNS bigint
      AS 'MODULE_PATHNAME', 'pg_database_size'
--- 8,10 ----
  
! CREATE OR REPLACE FUNCTION pg_database_size(oid) RETURNS bigint
      AS 'MODULE_PATHNAME', 'pg_database_size'
***************
*** 16,18 ****
  
! CREATE FUNCTION pg_relation_size(oid) RETURNS bigint
      AS 'MODULE_PATHNAME', 'pg_relation_size'
--- 12,14 ----
  
! CREATE OR REPLACE FUNCTION pg_relation_size(oid) RETURNS bigint
      AS 'MODULE_PATHNAME', 'pg_relation_size'
***************
*** 20,23 ****
  
! CREATE FUNCTION pg_size_pretty(bigint) RETURNS text
      AS 'MODULE_PATHNAME', 'pg_size_pretty'
      LANGUAGE C STRICT;
--- 16,132 ----
  
! CREATE OR REPLACE FUNCTION pg_size_pretty(bigint) RETURNS text
      AS 'MODULE_PATHNAME', 'pg_size_pretty'
      LANGUAGE C STRICT;
+ 
+ CREATE OR REPLACE FUNCTION relation_size (text) RETURNS bigint
+     AS 'MODULE_PATHNAME', 'relation_size'
+     LANGUAGE C STRICT;
+ 
+ CREATE OR REPLACE FUNCTION aggregate_relation_size (text) RETURNS bigint AS '
+ SELECT pg_relation_size(r.oid)
+      + COALESCE(pg_relation_size(t.oid), 0)::bigint
+      + COALESCE(pg_relation_size(ti.oid), 0)::bigint
+      + COALESCE(SUM(pg_relation_size(i.indexrelid)), 0)::bigint
+      + COALESCE(SUM(pg_relation_size(it.oid)), 0)::bigint
+      + COALESCE(SUM(pg_relation_size(iti.oid)), 0)::bigint AS bytes
+ FROM pg_class r 
+      LEFT JOIN pg_class t   ON (r.reltoastrelid = t.oid) 
+      LEFT JOIN pg_class ti  ON (t.reltoastidxid = ti.oid) 
+      LEFT JOIN pg_index i   ON (r.oid = i.indrelid) 
+      LEFT JOIN pg_class ir  ON (ir.oid = i.indexrelid) 
+      LEFT JOIN pg_class it  ON (ir.reltoastrelid = it.oid) 
+      LEFT JOIN pg_class iti ON (it.reltoastidxid = iti.oid) 
+ WHERE r.relname = \$1 
+ GROUP BY r.oid, t.oid, ti.oid
+ ' LANGUAGE SQL;
+ 
+ CREATE OR REPLACE FUNCTION indexes_size (text) RETURNS bigint 
+     AS '
+ SELECT COALESCE(SUM(pg_relation_size(ir.oid)), 0)::bigint
+      + COALESCE(SUM(pg_relation_size(it.oid)), 0)::bigint
+      + COALESCE(SUM(pg_relation_size(iti.oid)), 0)::bigint AS bytes
+ FROM pg_class r 
+      LEFT JOIN pg_index i   ON (r.oid = i.indrelid) 
+      LEFT JOIN pg_class ir  ON (ir.oid = i.indexrelid) 
+      LEFT JOIN pg_class it  ON (ir.reltoastrelid = it.oid) 
+      LEFT JOIN pg_class iti ON (it.reltoastidxid = iti.oid) 
+ WHERE r.relname = \$1 
+ ' LANGUAGE SQL;
+ 
+ CREATE OR REPLACE FUNCTION relation_size_components (text) RETURNS SETOF RECORD
+     AS '
+ -- relation size
+ SELECT indexes_size(r.relname) AS indexes_size, 
+        relation_size(r.relname) AS data_size, 
+        aggregate_relation_size(r.relname) AS total_size, 
+        r.relname, r.relkind, r.oid AS relid, r.relfilenode 
+ FROM pg_class r 
+ WHERE r.relname = \$1 
+ 
+ UNION ALL 
+ 
+ -- relation toast size
+ SELECT indexes_size(toast.relname) AS indexes_size, 
+        relation_size(''pg_toast.''||toast.relname) AS data_size, 
+        aggregate_relation_size(toast.relname) AS total_size, 
+        toast.relname, toast.relkind, toast.oid AS relid, toast.relfilenode 
+ FROM pg_class r, pg_class toast
+ WHERE r.reltoastrelid = toast.oid 
+   AND r.relname = \$1 
+ 
+ UNION ALL 
+ 
+ -- relation toast index size
+ SELECT indexes_size(toastidxr.relname) AS indexes_size, 
+        relation_size(''pg_toast.''||toastidxr.relname) AS data_size, 
+        aggregate_relation_size(toastidxr.relname) AS total_size, 
+        toastidxr.relname, toastidxr.relkind, 
+        toastidxr.oid AS relid, toastidxr.relfilenode 
+ FROM pg_class r, pg_index toastidx, pg_class toastidxr
+ WHERE r.relname = \$1
+   AND r.reltoastrelid = toastidx.indrelid 
+   AND toastidx.indexrelid = toastidxr.oid 
+ 
+ UNION ALL 
+ 
+ -- relation indices size
+ SELECT indexes_size(idxr.relname) AS indexes_size, 
+        relation_size(idxr.relname) AS data_size, 
+        aggregate_relation_size(idxr.relname) AS total_size, 
+        idxr.relname, idxr.relkind, idxr.oid AS relid, idxr.relfilenode 
+ FROM pg_class r, pg_class idxr, pg_index idx 
+ WHERE r.relname = \$1
+   AND r.oid = idx.indrelid
+   AND idx.indexrelid = idxr.oid 
+ 
+ UNION ALL 
+ 
+ -- relation indices toast size
+ SELECT indexes_size(idxtoastr.relname) AS indexes_size, 
+        relation_size(''pg_toast.''||idxtoastr.relname) AS data_size, 
+        aggregate_relation_size(idxtoastr.relname) AS total_size, 
+        idxtoastr.relname, idxtoastr.relkind, idxtoastr.oid AS relid, 
+        idxtoastr.relfilenode 
+ FROM pg_class r, pg_class idxr, pg_index idx, pg_class idxtoastr
+ WHERE r.relname = \$1
+   AND r.oid = idx.indrelid
+   AND idx.indexrelid = idxr.oid 
+   AND idxr.reltoastrelid = idxtoastr.oid 
+ 
+ UNION ALL 
+ 
+ -- relation indices toast index size
+ SELECT indexes_size(idxtoastidxr.relname) AS indexes_size, 
+        relation_size(''pg_toast.''||idxtoastidxr.relname) AS data_size, 
+        aggregate_relation_size(idxtoastidxr.relname) AS total_size, 
+        idxtoastidxr.relname, idxtoastidxr.relkind, 
+        idxtoastidxr.oid AS relid, idxtoastidxr.relfilenode 
+ FROM pg_class r, pg_class idxr, pg_index idx, pg_class idxtoast, 
+      pg_class idxtoastidxr
+ WHERE r.relname = \$1
+   AND r.oid = idx.indrelid
+   AND idx.indexrelid = idxr.oid 
+   AND idxr.reltoastrelid = idxtoast.oid 
+   AND idxtoast.reltoastrelid = idxtoastidxr.oid 
+ ' LANGUAGE SQL;
+ 
---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
      joining column's datatypes do not match

Reply via email to