Commit 8828689a authored by Tom Lane's avatar Tom Lane

Make an editorial pass over the newly SGML-ified contrib documentation.

Fix lots of bad markup, bad English, bad explanations.

Second round of commits.  pgcrypto and pgstandby still to go...
parent a3102ce1
<!-- $PostgreSQL: pgsql/doc/src/sgml/intagg.sgml,v 1.3 2007/12/10 05:32:51 tgl Exp $ -->
<sect1 id="intagg"> <sect1 id="intagg">
<title>intagg</title> <title>intagg</title>
...@@ -7,22 +8,73 @@ ...@@ -7,22 +8,73 @@
</indexterm> </indexterm>
<para> <para>
This section describes the <literal>intagg</literal> module which provides an integer aggregator and an enumerator. The <filename>intagg</filename> module provides an integer aggregator and an
enumerator.
</para> </para>
<sect2>
<title>Functions</title>
<para>
The aggregator is an aggregate function
<function>int_array_aggregate(integer)</>
that produces an integer array
containing exactly the integers it is fed.
Here is a not-tremendously-useful example:
</para>
<programlisting>
test=# select int_array_aggregate(i) from
test-# generate_series(1,10,2) i;
int_array_aggregate
---------------------
{1,3,5,7,9}
(1 row)
</programlisting>
<para>
The enumerator is a function
<function>int_array_enum(integer[])</>
that returns <type>setof integer</>. It is essentially the reverse
operation of the aggregator: given an array of integers, expand it
into a set of rows. For example,
</para>
<programlisting>
test=# select * from int_array_enum(array[1,3,5,7,9]);
int_array_enum
----------------
1
3
5
7
9
(5 rows)
</programlisting>
</sect2>
<sect2>
<title>Sample Uses</title>
<para> <para>
Many database systems have the notion of a one to many table. Such a table usually sits between two indexed tables, as: Many database systems have the notion of a one to many table. Such a table
usually sits between two indexed tables, for example:
</para> </para>
<programlisting> <programlisting>
CREATE TABLE one_to_many(left INT, right INT) ; CREATE TABLE left (id INT PRIMARY KEY, ...);
CREATE TABLE right (id INT PRIMARY KEY, ...);
CREATE TABLE one_to_many(left INT REFERENCES left, right INT REFERENCES right);
</programlisting> </programlisting>
<para> <para>
And it is used like this: It is typically used like this:
</para> </para>
<programlisting> <programlisting>
SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right) SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right)
WHERE one_to_many.left = item; WHERE one_to_many.left = <replaceable>item</>;
</programlisting> </programlisting>
<para> <para>
...@@ -32,8 +84,8 @@ CREATE TABLE one_to_many(left INT, right INT) ; ...@@ -32,8 +84,8 @@ CREATE TABLE one_to_many(left INT, right INT) ;
<para> <para>
Now, this methodology can be cumbersome with a very large number of Now, this methodology can be cumbersome with a very large number of
entries in the one_to_many table. Depending on the order in which entries in the <structname>one_to_many</> table. Often,
data was entered, a join like this could result in an index scan a join like this would result in an index scan
and a fetch for each right hand entry in the table for a particular and a fetch for each right hand entry in the table for a particular
left hand entry. If you have a very dynamic system, there is not much you left hand entry. If you have a very dynamic system, there is not much you
can do. However, if you have some data which is fairly static, you can can do. However, if you have some data which is fairly static, you can
...@@ -41,42 +93,53 @@ CREATE TABLE one_to_many(left INT, right INT) ; ...@@ -41,42 +93,53 @@ CREATE TABLE one_to_many(left INT, right INT) ;
</para> </para>
<programlisting> <programlisting>
CREATE TABLE summary as SELECT left, int_array_aggregate(right) CREATE TABLE summary as
AS right FROM one_to_many GROUP BY left; SELECT left, int_array_aggregate(right) AS right
FROM one_to_many
GROUP BY left;
</programlisting> </programlisting>
<para> <para>
This will create a table with one row per left item, and an array This will create a table with one row per left item, and an array
of right items. Now this is pretty useless without some way of using of right items. Now this is pretty useless without some way of using
the array, thats why there is an array enumerator. the array; that's why there is an array enumerator. You can do
</para> </para>
<programlisting> <programlisting>
SELECT left, int_array_enum(right) FROM summary WHERE left = item; SELECT left, int_array_enum(right) FROM summary WHERE left = <replaceable>item</>;
</programlisting> </programlisting>
<para> <para>
The above query using int_array_enum, produces the same results as: The above query using <function>int_array_enum</> produces the same results
as
</para> </para>
<programlisting> <programlisting>
SELECT left, right FROM one_to_many WHERE left = item; SELECT left, right FROM one_to_many WHERE left = <replaceable>item</>;
</programlisting> </programlisting>
<para> <para>
The difference is that the query against the summary table has to get The difference is that the query against the summary table has to get
only one row from the table, where as the query against "one_to_many" only one row from the table, whereas the direct query against
must index scan and fetch a row for each entry. <structname>one_to_many</> must index scan and fetch a row for each entry.
</para> </para>
<para> <para>
On our system, an EXPLAIN shows a query with a cost of 8488 gets reduced On one system, an <command>EXPLAIN</> showed a query with a cost of 8488 was
to a cost of 329. The query is a join between the one_to_many table, reduced to a cost of 329. The original query was a join involving the
<structname>one_to_many</> table, which was replaced by:
</para> </para>
<programlisting> <programlisting>
SELECT right, count(right) FROM SELECT right, count(right) FROM
( ( SELECT left, int_array_enum(right) AS right
SELECT left, int_array_enum(right) AS right FROM summary JOIN FROM summary JOIN (SELECT left FROM left_table WHERE left = <replaceable>item</>) AS lefts
(SELECT left FROM left_table WHERE left = item) AS lefts ON (summary.left = lefts.left)
ON (summary.left = lefts.left ) ) AS list
) AS list GROUP BY right ORDER BY count DESC ; GROUP BY right
ORDER BY count DESC;
</programlisting> </programlisting>
</sect1>
</sect2>
</sect1>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<!-- $PostgreSQL: pgsql/doc/src/sgml/oid2name.sgml,v 1.3 2007/12/10 05:32:51 tgl Exp $ -->
<sect1 id="oid2name"> <sect1 id="oid2name">
<title>oid2name</title> <title>oid2name</title>
...@@ -6,65 +8,150 @@ ...@@ -6,65 +8,150 @@
</indexterm> </indexterm>
<para> <para>
This utility allows administrators to examine the file structure used by <application>oid2name</> is a utility program that helps administrators to
PostgreSQL. To make use of it, you need to be familiar with the file examine the file structure used by PostgreSQL. To make use of it, you need
structure, which is described in <xref linkend="storage">. to be familiar with the database file structure, which is described in
<xref linkend="storage">.
</para> </para>
<sect2> <note>
<title>Overview</title>
<para> <para>
<literal>oid2name</literal> connects to the database and extracts OID, The name <quote>oid2name</> is historical, and is actually rather
filenode, and table name information. You can also have it show database misleading, since most of the time when you use it, you will really
OIDs and tablespace OIDs. be concerned with tables' filenode numbers (which are the file names
</para> visible in the database directories). Be sure you understand the
<para> difference between table OIDs and table filenodes!
When displaying specific tables, you can select which tables to show by
using -o, -f and -t. The first switch takes an OID, the second takes
a filenode, and the third takes a tablename (actually, it's a LIKE
pattern, so you can use things like "foo%"). Note that you can use as many
of these switches as you like, and the listing will include all objects
matched by any of the switches. Also note that these switches can only
show objects in the database given in -d.
</para> </para>
</note>
<sect2>
<title>Overview</title>
<para> <para>
If you don't give any of -o, -f or -t it will dump all the tables in the <application>oid2name</application> connects to a target database and
database given in -d. If you don't give -d, it will show a database extracts OID, filenode, and/or table name information. You can also have
listing. Alternatively you can give -s to get a tablespace listing. it show database OIDs or tablespace OIDs. The program is controlled by
a large number of command-line switches, as shown in
<xref linkend="oid2name-switches">.
</para> </para>
<table>
<title>Additional switches</title> <table id="oid2name-switches">
<title><application>oid2name</> switches</title>
<tgroup cols="2"> <tgroup cols="2">
<thead>
<row>
<entry>Switch</entry>
<entry>Description</entry>
</row>
</thead>
<tbody> <tbody>
<row>
<entry><literal>-o</literal> <replaceable>oid</></entry>
<entry>show info for table with OID <replaceable>oid</></entry>
</row>
<row>
<entry><literal>-f</literal> <replaceable>filenode</></entry>
<entry>show info for table with filenode <replaceable>filenode</></entry>
</row>
<row>
<entry><literal>-t</literal> <replaceable>tablename_pattern</></entry>
<entry>show info for table(s) matching <replaceable>tablename_pattern</></entry>
</row>
<row>
<entry><literal>-s</literal></entry>
<entry>show tablespace OIDs</entry>
</row>
<row>
<entry><literal>-S</literal></entry>
<entry>include system objects (those in
<literal>information_schema</literal>, <literal>pg_toast</literal>
and <literal>pg_catalog</literal> schemas)
</entry>
</row>
<row> <row>
<entry><literal>-i</literal></entry> <entry><literal>-i</literal></entry>
<entry>include indexes and sequences in the database listing.</entry> <entry>include indexes and sequences in the listing</entry>
</row> </row>
<row> <row>
<entry><literal>-x</literal></entry> <entry><literal>-x</literal></entry>
<entry>display more information about each object shown: tablespace name, <entry>display more information about each object shown: tablespace name,
schema name, OID. schema name, and OID
</entry> </entry>
</row> </row>
<row> <row>
<entry><literal>-S</literal></entry> <entry><literal>-q</literal></entry>
<entry>also show system objects (those in information_schema, pg_toast <entry>omit headers (useful for scripting)</entry>
and pg_catalog schemas)
</entry>
</row> </row>
<row> <row>
<entry><literal>-q</literal></entry> <entry><literal>-d</literal> <replaceable>database</></entry>
<entry>don't display headers(useful for scripting)</entry> <entry>database to connect to</entry>
</row>
<row>
<entry><literal>-H</literal> <replaceable>host</></entry>
<entry>database server's host</entry>
</row>
<row>
<entry><literal>-p</literal> <replaceable>port</></entry>
<entry>database server's port</entry>
</row>
<row>
<entry><literal>-U</literal> <replaceable>username</></entry>
<entry>username to connect as</entry>
</row>
<row>
<entry><literal>-P</literal> <replaceable>password</></entry>
<entry>password (deprecated &mdash; putting this on the command line
is a security hazard)</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
<para>
To display specific tables, select which tables to show by
using <literal>-o</>, <literal>-f</> and/or <literal>-t</>.
<literal>-o</> takes an OID,
<literal>-f</> takes a filenode,
and <literal>-t</> takes a tablename (actually, it's a LIKE
pattern, so you can use things like <literal>foo%</>).
You can use as many
of these switches as you like, and the listing will include all objects
matched by any of the switches. But note that these switches can only
show objects in the database given by <literal>-d</>.
</para>
<para>
If you don't give any of <literal>-o</>, <literal>-f</> or <literal>-t</>,
but do give <literal>-d</>, it will list all tables in the database
named by <literal>-d</>. In this mode, the <literal>-S</> and
<literal>-i</> switches control what gets listed.
</para>
<para>
If you don't give <literal>-d</> either, it will show a listing of database
OIDs. Alternatively you can give <literal>-s</> to get a tablespace
listing.
</para>
</sect2> </sect2>
<sect2> <sect2>
<title>Examples</title> <title>Examples</title>
<programlisting> <programlisting>
$ # what's in this database server, anyway?
$ oid2name $ oid2name
All databases: All databases:
Oid Database Name Tablespace Oid Database Name Tablespace
...@@ -83,7 +170,8 @@ All tablespaces: ...@@ -83,7 +170,8 @@ All tablespaces:
155151 fastdisk 155151 fastdisk
155152 bigdisk 155152 bigdisk
$ cd $PGDATA/17228 $ # OK, let's look into database alvherre
$ cd $PGDATA/base/17228
$ # get top 10 db objects in the default tablespace, ordered by size $ # get top 10 db objects in the default tablespace, ordered by size
$ ls -lS * | head -10 $ ls -lS * | head -10
...@@ -98,6 +186,7 @@ $ ls -lS * | head -10 ...@@ -98,6 +186,7 @@ $ ls -lS * | head -10
-rw------- 1 alvherre alvherre 163840 sep 14 09:50 16699 -rw------- 1 alvherre alvherre 163840 sep 14 09:50 16699
-rw------- 1 alvherre alvherre 122880 sep 6 17:51 16751 -rw------- 1 alvherre alvherre 122880 sep 6 17:51 16751
$ # I wonder what file 155173 is ...
$ oid2name -d alvherre -f 155173 $ oid2name -d alvherre -f 155173
From database "alvherre": From database "alvherre":
Filenode Table Name Filenode Table Name
...@@ -112,7 +201,7 @@ From database "alvherre": ...@@ -112,7 +201,7 @@ From database "alvherre":
155173 accounts 155173 accounts
1155291 accounts_pkey 1155291 accounts_pkey
$ # you can also mix the options, and have more details $ # you can mix the options, and get more details with -x
$ oid2name -d alvherre -t accounts -f 1155291 -x $ oid2name -d alvherre -t accounts -f 1155291 -x
From database "alvherre": From database "alvherre":
Filenode Table Name Oid Schema Tablespace Filenode Table Name Oid Schema Tablespace
...@@ -178,28 +267,25 @@ From database "alvherre": ...@@ -178,28 +267,25 @@ From database "alvherre":
Filenode Table Name Filenode Table Name
---------------------- ----------------------
155156 foo 155156 foo
$ # end of sample session.
</programlisting> </programlisting>
</sect2>
<sect2>
<title>Limitations</title>
<para> <para>
You can also get approximate size data for each object using psql. For <application>oid2name</> requires a running database server with
example, non-corrupt system catalogs. It is therefore of only limited use
</para> for recovering from catastrophic database corruption situations.
<programlisting>
SELECT relpages, relfilenode, relname FROM pg_class ORDER BY relpages DESC;
</programlisting>
<para>
Each page is typically 8k. Relpages is updated by VACUUM.
</para> </para>
</sect2> </sect2>
<sect2> <sect2>
<title>Author</title> <title>Author</title>
<para> <para>
b. palmer, <email>bpalmer@crimelabs.net</email> B. Palmer <email>bpalmer@crimelabs.net</email>
</para> </para>
</sect2> </sect2>
</sect1> </sect1>
<!-- $PostgreSQL: pgsql/doc/src/sgml/pageinspect.sgml,v 1.3 2007/12/10 05:32:51 tgl Exp $ -->
<sect1 id="pageinspect"> <sect1 id="pageinspect">
<title>pageinspect</title> <title>pageinspect</title>
...@@ -7,107 +8,151 @@ ...@@ -7,107 +8,151 @@
</indexterm> </indexterm>
<para> <para>
The functions in this module allow you to inspect the contents of data pages The <filename>pageinspect</> module provides functions that allow you to
at a low level, for debugging purposes. inspect the contents of database pages at a low level, which is useful for
debugging purposes. All of these functions may be used only by superusers.
</para> </para>
<sect2> <sect2>
<title>Functions included</title> <title>Functions</title>
<variablelist>
<varlistentry>
<term>
<function>get_raw_page(text, int) returns bytea</function>
</term>
<itemizedlist>
<listitem> <listitem>
<para> <para>
<literal>get_raw_page</literal> reads one block of the named table and returns a copy as a <function>get_raw_page</function> reads the specified block of the named
bytea field. This allows a single time-consistent copy of the block to be table and returns a copy as a <type>bytea</> value. This allows a
made. Use of this functions is restricted to superusers. single time-consistent copy of the block to be obtained.
</para> </para>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>page_header(bytea) returns record</function>
</term>
<listitem> <listitem>
<para> <para>
<literal>page_header</literal> shows fields which are common to all PostgreSQL heap and index <function>page_header</function> shows fields that are common to all
pages. Use of this function is restricted to superusers. <productname>PostgreSQL</> heap and index pages.
</para> </para>
<para> <para>
A page image obtained with <literal>get_raw_page</literal> should be passed as argument: A page image obtained with <function>get_raw_page</function> should be
passed as argument. For example:
</para> </para>
<programlisting> <programlisting>
regression=# SELECT * FROM page_header(get_raw_page('pg_class',0)); test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
lsn | tli | flags | lower | upper | special | pagesize | version | prune_xid lsn | tli | flags | lower | upper | special | pagesize | version | prune_xid
-----------+-----+-------+-------+-------+---------+----------+---------+----------- -----------+-----+-------+-------+-------+---------+----------+---------+-----------
0/24A1B50 | 1 | 1 | 232 | 368 | 8192 | 8192 | 4 | 0 0/24A1B50 | 1 | 1 | 232 | 368 | 8192 | 8192 | 4 | 0
</programlisting> </programlisting>
<para> <para>
The returned columns correspond to the fields in the PageHeaderData struct. The returned columns correspond to the fields in the
See src/include/storage/bufpage.h for more details. <structname>PageHeaderData</> struct.
See <filename>src/include/storage/bufpage.h</> for details.
</para> </para>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>heap_page_items(bytea) returns setof record</function>
</term>
<listitem> <listitem>
<para> <para>
<literal>heap_page_items</literal> shows all line pointers on a heap page. For those line <function>heap_page_items</function> shows all line pointers on a heap
pointers that are in use, tuple headers are also shown. All tuples are page. For those line pointers that are in use, tuple headers are also
shown, whether or not the tuples were visible to an MVCC snapshot at the shown. All tuples are shown, whether or not the tuples were visible to
time the raw page was copied. Use of this function is restricted to an MVCC snapshot at the time the raw page was copied.
superusers.
</para> </para>
<para> <para>
A heap page image obtained with <literal>get_raw_page</literal> should be passed as argument: A heap page image obtained with <function>get_raw_page</function> should
be passed as argument. For example:
</para> </para>
<programlisting> <programlisting>
test=# SELECT * FROM heap_page_items(get_raw_page('pg_class',0)); test=# SELECT * FROM heap_page_items(get_raw_page('pg_class', 0));
</programlisting> </programlisting>
<para> <para>
See src/include/storage/itemid.h and src/include/access/htup.h for See <filename>src/include/storage/itemid.h</> and
explanations of the fields returned. <filename>src/include/access/htup.h</> for explanations of the fields
returned.
</para> </para>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>bt_metap(text) returns record</function>
</term>
<listitem> <listitem>
<para> <para>
<literal>bt_metap()</literal> returns information about the btree index metapage: <function>bt_metap</function> returns information about a btree
index's metapage. For example:
</para> </para>
<programlisting> <programlisting>
test=> SELECT * FROM bt_metap('pg_cast_oid_index'); test=# SELECT * FROM bt_metap('pg_cast_oid_index');
-[ RECORD 1 ]----- -[ RECORD 1 ]-----
magic | 340322 magic | 340322
version | 2 version | 2
root | 1 root | 1
level | 0 level | 0
fastroot | 1 fastroot | 1
fastlevel | 0 fastlevel | 0
</programlisting> </programlisting>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>bt_page_stats(text, int) returns record</function>
</term>
<listitem> <listitem>
<para> <para>
<literal>bt_page_stats()</literal> shows information about single btree pages: <function>bt_page_stats</function> returns summary information about
single pages of btree indexes. For example:
</para> </para>
<programlisting> <programlisting>
test=> SELECT * FROM bt_page_stats('pg_cast_oid_index', 1); test=# SELECT * FROM bt_page_stats('pg_cast_oid_index', 1);
-[ RECORD 1 ]-+----- -[ RECORD 1 ]-+-----
blkno | 1 blkno | 1
type | l type | l
live_items | 256 live_items | 256
dead_items | 0 dead_items | 0
avg_item_size | 12 avg_item_size | 12
page_size | 8192 page_size | 8192
free_size | 4056 free_size | 4056
btpo_prev | 0 btpo_prev | 0
btpo_next | 0 btpo_next | 0
btpo | 0 btpo | 0
btpo_flags | 3 btpo_flags | 3
</programlisting> </programlisting>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>bt_page_items(text, int) returns setof record</function>
</term>
<listitem> <listitem>
<para> <para>
<literal>bt_page_items()</literal> returns information about specific items on btree pages: <function>bt_page_items</function> returns detailed information about
all of the items on a btree index page. For example:
</para> </para>
<programlisting> <programlisting>
test=> SELECT * FROM bt_page_items('pg_cast_oid_index', 1); test=# SELECT * FROM bt_page_items('pg_cast_oid_index', 1);
itemoffset | ctid | itemlen | nulls | vars | data itemoffset | ctid | itemlen | nulls | vars | data
------------+---------+---------+-------+------+------------- ------------+---------+---------+-------+------+-------------
1 | (0,1) | 12 | f | f | 23 27 00 00 1 | (0,1) | 12 | f | f | 23 27 00 00
2 | (0,2) | 12 | f | f | 24 27 00 00 2 | (0,2) | 12 | f | f | 24 27 00 00
3 | (0,3) | 12 | f | f | 25 27 00 00 3 | (0,3) | 12 | f | f | 25 27 00 00
...@@ -118,7 +163,8 @@ regression=# SELECT * FROM page_header(get_raw_page('pg_class',0)); ...@@ -118,7 +163,8 @@ regression=# SELECT * FROM page_header(get_raw_page('pg_class',0));
8 | (0,8) | 12 | f | f | 2a 27 00 00 8 | (0,8) | 12 | f | f | 2a 27 00 00
</programlisting> </programlisting>
</listitem> </listitem>
</itemizedlist> </varlistentry>
</variablelist>
</sect2> </sect2>
</sect1>
</sect1>
This diff is collapsed.
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbuffercache.sgml,v 2.2 2007/12/10 05:32:51 tgl Exp $ -->
<sect1 id="pgbuffercache"> <sect1 id="pgbuffercache">
<title>pg_buffercache</title> <title>pg_buffercache</title>
...@@ -6,48 +8,116 @@ ...@@ -6,48 +8,116 @@
</indexterm> </indexterm>
<para> <para>
The <literal>pg_buffercache</literal> module provides a means for examining The <filename>pg_buffercache</filename> module provides a means for
what's happening to the buffercache at any given time without having to examining what's happening in the shared buffer cache in real time.
restart or rebuild the server with debugging code added. The intent is to
do for the buffercache what pg_locks does for locks.
</para> </para>
<para> <para>
This module consists of a C function <literal>pg_buffercache_pages()</literal> The module provides a C function <function>pg_buffercache_pages</function>
that returns a set of records, plus a view <literal>pg_buffercache</literal> that returns a set of records, plus a view
to wrapper the function. <structname>pg_buffercache</structname> that wraps the function for
convenient use.
</para> </para>
<para> <para>
By default public access is REVOKED from both of these, just in case there By default public access is revoked from both of these, just in case there
are security issues lurking. are security issues lurking.
</para> </para>
<sect2> <sect2>
<title>Notes</title> <title>The <structname>pg_buffercache</structname> view</title>
<para> <para>
The definition of the columns exposed in the view is: The definitions of the columns exposed by the view are:
</para> </para>
<programlisting>
Column | references | Description <table>
----------------+----------------------+------------------------------------ <title><structname>pg_buffercache</> Columns</title>
bufferid | | Id, 1..shared_buffers.
relfilenode | pg_class.relfilenode | Refilenode of the relation. <tgroup cols="4">
reltablespace | pg_tablespace.oid | Tablespace oid of the relation. <thead>
reldatabase | pg_database.oid | Database for the relation. <row>
relblocknumber | | Offset of the page in the relation. <entry>Name</entry>
isdirty | | Is the page dirty? <entry>Type</entry>
usagecount | | Page LRU count <entry>References</entry>
</programlisting> <entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>bufferid</structfield></entry>
<entry><type>integer</type></entry>
<entry></entry>
<entry>ID, in the range 1..<varname>shared_buffers</></entry>
</row>
<row>
<entry><structfield>relfilenode</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal>pg_class.relfilenode</literal></entry>
<entry>Relfilenode of the relation</entry>
</row>
<row>
<entry><structfield>reltablespace</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal>pg_tablespace.oid</literal></entry>
<entry>Tablespace OID of the relation</entry>
</row>
<row>
<entry><structfield>reldatabase</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal>pg_database.oid</literal></entry>
<entry>Database OID of the relation</entry>
</row>
<row>
<entry><structfield>relblocknumber</structfield></entry>
<entry><type>bigint</type></entry>
<entry></entry>
<entry>Page number within the relation</entry>
</row>
<row>
<entry><structfield>isdirty</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry>Is the page dirty?</entry>
</row>
<row>
<entry><structfield>usagecount</structfield></entry>
<entry><type>smallint</type></entry>
<entry></entry>
<entry>Page LRU count</entry>
</row>
</tbody>
</tgroup>
</table>
<para> <para>
There is one row for each buffer in the shared cache. Unused buffers are There is one row for each buffer in the shared cache. Unused buffers are
shown with all fields null except bufferid. shown with all fields null except <structfield>bufferid</>. Shared system
catalogs are shown as belonging to database zero.
</para> </para>
<para> <para>
Because the cache is shared by all the databases, there are pages from Because the cache is shared by all the databases, there will normally be
relations not belonging to the current database. pages from relations not belonging to the current database. This means
that there may not be matching join rows in <structname>pg_class</> for
some rows, or that there could even be incorrect joins. If you are
trying to join against <structname>pg_class</>, it's a good idea to
restrict the join to rows having <structfield>reldatabase</> equal to
the current database's OID or zero.
</para> </para>
<para> <para>
When the pg_buffercache view is accessed, internal buffer manager locks are When the <structname>pg_buffercache</> view is accessed, internal buffer
taken, and a copy of the buffer cache data is made for the view to display. manager locks are taken for long enough to copy all the buffer state
data that the view will display.
This ensures that the view produces a consistent set of results, while not This ensures that the view produces a consistent set of results, while not
blocking normal buffer activity longer than necessary. Nonetheless there blocking normal buffer activity longer than necessary. Nonetheless there
could be some impact on database performance if this view is read often. could be some impact on database performance if this view is read often.
...@@ -56,30 +126,13 @@ ...@@ -56,30 +126,13 @@
<sect2> <sect2>
<title>Sample output</title> <title>Sample output</title>
<programlisting>
regression=# \d pg_buffercache;
View "public.pg_buffercache"
Column | Type | Modifiers
----------------+----------+-----------
bufferid | integer |
relfilenode | oid |
reltablespace | oid |
reldatabase | oid |
relblocknumber | bigint |
isdirty | boolean |
usagecount | smallint |
View definition:
SELECT p.bufferid, p.relfilenode, p.reltablespace, p.reldatabase,
p.relblocknumber, p.isdirty, p.usagecount
FROM pg_buffercache_pages() p(bufferid integer, relfilenode oid,
reltablespace oid, reldatabase oid, relblocknumber bigint,
isdirty boolean, usagecount smallint);
<programlisting>
regression=# SELECT c.relname, count(*) AS buffers regression=# SELECT c.relname, count(*) AS buffers
FROM pg_class c INNER JOIN pg_buffercache b FROM pg_buffercache b INNER JOIN pg_class c
ON b.relfilenode = c.relfilenode INNER JOIN pg_database d ON b.relfilenode = c.relfilenode AND
ON (b.reldatabase = d.oid AND d.datname = current_database()) b.reldatabase IN (0, (SELECT oid FROM pg_database
WHERE datname = current_database()))
GROUP BY c.relname GROUP BY c.relname
ORDER BY 2 DESC LIMIT 10; ORDER BY 2 DESC LIMIT 10;
relname | buffers relname | buffers
...@@ -95,26 +148,23 @@ ...@@ -95,26 +148,23 @@
pg_depend | 22 pg_depend | 22
pg_depend_reference_index | 20 pg_depend_reference_index | 20
(10 rows) (10 rows)
regression=#
</programlisting> </programlisting>
</sect2> </sect2>
<sect2> <sect2>
<title>Authors</title> <title>Authors</title>
<itemizedlist>
<listitem>
<para> <para>
Mark Kirkwood <email>markir@paradise.net.nz</email> Mark Kirkwood <email>markir@paradise.net.nz</email>
</para> </para>
</listitem>
<listitem> <para>
<para>Design suggestions: Neil Conway <email>neilc@samurai.com</email></para> Design suggestions: Neil Conway <email>neilc@samurai.com</email>
</listitem> </para>
<listitem>
<para>Debugging advice: Tom Lane <email>tgl@sss.pgh.pa.us</email></para> <para>
</listitem> Debugging advice: Tom Lane <email>tgl@sss.pgh.pa.us</email>
</itemizedlist> </para>
</sect2> </sect2>
</sect1> </sect1>
This diff is collapsed.
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgrowlocks.sgml,v 1.4 2007/12/10 05:32:51 tgl Exp $ -->
<sect1 id="pgrowlocks"> <sect1 id="pgrowlocks">
<title>pgrowlocks</title> <title>pgrowlocks</title>
...@@ -7,106 +8,112 @@ ...@@ -7,106 +8,112 @@
</indexterm> </indexterm>
<para> <para>
The <literal>pgrowlocks</literal> module provides a function to show row The <filename>pgrowlocks</filename> module provides a function to show row
locking information for a specified table. locking information for a specified table.
</para> </para>
<sect2> <sect2>
<title>Overview</title> <title>Overview</title>
<programlisting>
pgrowlocks(text) RETURNS pgrowlocks_type <synopsis>
</programlisting> pgrowlocks(text) returns setof record
</synopsis>
<para> <para>
The parameter is a name of table. And <literal>pgrowlocks_type</literal> is The parameter is the name of a table. The result is a set of records,
defined as: with one row for each locked row within the table. The output columns
are:
</para> </para>
<programlisting>
CREATE TYPE pgrowlocks_type AS (
locked_row TID, -- row TID
lock_type TEXT, -- lock type
locker XID, -- locking XID
multi bool, -- multi XID?
xids xid[], -- multi XIDs
pids INTEGER[] -- locker's process id
);
</programlisting>
<table> <table>
<title>pgrowlocks_type</title> <title><function>pgrowlocks</> output columns</title>
<tgroup cols="2">
<tgroup cols="3">
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody> <tbody>
<row> <row>
<entry>locked_row</entry> <entry><structfield>locked_row</structfield></entry>
<entry>tuple ID(TID) of each locked rows</entry> <entry><type>tid</type></entry>
<entry>Tuple ID (TID) of locked row</entry>
</row> </row>
<row> <row>
<entry>lock_type</entry> <entry><structfield>lock_type</structfield></entry>
<entry>"Shared" for shared lock, "Exclusive" for exclusive lock</entry> <entry><type>text</type></entry>
<entry><literal>Shared</> for shared lock, or
<literal>Exclusive</> for exclusive lock</entry>
</row> </row>
<row> <row>
<entry>locker</entry> <entry><structfield>locker</structfield></entry>
<entry>transaction ID of locker (Note 1)</entry> <entry><type>xid</type></entry>
<entry>Transaction ID of locker, or multixact ID if multi-transaction</entry>
</row> </row>
<row> <row>
<entry>multi</entry> <entry><structfield>multi</structfield></entry>
<entry>"t" if locker is a multi transaction, otherwise "f"</entry> <entry><type>boolean</type></entry>
<entry>True if locker is a multi-transaction</entry>
</row> </row>
<row> <row>
<entry>xids</entry> <entry><structfield>xids</structfield></entry>
<entry>XIDs of lockers (Note 2)</entry> <entry><type>xid[]</type></entry>
<entry>Transaction IDs of lockers (more than one if multi-transaction)</entry>
</row> </row>
<row> <row>
<entry>pids</entry> <entry><structfield>pids</structfield></entry>
<entry>process ids of locking backends</entry> <entry><type>integer[]</type></entry>
<entry>Process IDs of locking backends (more than one if multi-transaction)</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
<para>
Note1: If the locker is multi transaction, it represents the multi ID.
</para>
<para>
Note2: If the locker is multi, multiple data are shown.
</para>
<para> <para>
The calling sequence for <literal>pgrowlocks</literal> is as follows: <function>pgrowlocks</function> takes <literal>AccessShareLock</> for the
<literal>pgrowlocks</literal> grabs AccessShareLock for the target table and target table and reads each row one by one to collect the row locking
reads each row one by one to get the row locking information. You should information. This is not very speedy for a large table. Note that:
notice that:
</para> </para>
<orderedlist> <orderedlist>
<listitem> <listitem>
<para> <para>
if the table is exclusive locked by someone else, If the table as a whole is exclusive-locked by someone else,
<literal>pgrowlocks</literal> will be blocked. <function>pgrowlocks</function> will be blocked.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<literal>pgrowlocks</literal> may show incorrect information if there's a <function>pgrowlocks</function> is not guaranteed to produce a
new lock or a lock is freeed while its execution. self-consistent snapshot. It is possible that a new row lock is taken,
or an old lock is freed, during its execution.
</para> </para>
</listitem> </listitem>
</orderedlist> </orderedlist>
<para> <para>
<literal>pgrowlocks</literal> does not show the contents of locked rows. If <function>pgrowlocks</function> does not show the contents of locked
you want to take a look at the row contents at the same time, you could do rows. If you want to take a look at the row contents at the same time, you
something like this: could do something like this:
</para>
<programlisting> <programlisting>
SELECT * FROM accounts AS a, pgrowlocks('accounts') AS p WHERE p.locked_ row = a.ctid; SELECT * FROM accounts AS a, pgrowlocks('accounts') AS p
WHERE p.locked_row = a.ctid;
</programlisting> </programlisting>
Be aware however that (as of <productname>PostgreSQL</> 8.3) such a
query will be very inefficient.
</para>
</sect2> </sect2>
<sect2> <sect2>
<title>Example</title> <title>Sample output</title>
<para>
<literal>pgrowlocks</literal> returns the following columns:
</para>
<para>
Here is a sample execution of pgrowlocks:
</para>
<programlisting> <programlisting>
test=# SELECT * FROM pgrowlocks('t1'); test=# SELECT * FROM pgrowlocks('t1');
locked_row | lock_type | locker | multi | xids | pids locked_row | lock_type | locker | multi | xids | pids
...@@ -117,7 +124,14 @@ test=# SELECT * FROM pgrowlocks('t1'); ...@@ -117,7 +124,14 @@ test=# SELECT * FROM pgrowlocks('t1');
(0,4) | Exclusive | 804 | f | {804} | {29066} (0,4) | Exclusive | 804 | f | {804} | {29066}
(4 rows) (4 rows)
</programlisting> </programlisting>
</sect2>
<sect2>
<title>Author</title>
<para>
Tatsuo Ishii
</para>
</sect2> </sect2>
</sect1>
</sect1>
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstattuple.sgml,v 1.3 2007/12/10 05:32:51 tgl Exp $ -->
<sect1 id="pgstattuple"> <sect1 id="pgstattuple">
<title>pgstattuple</title> <title>pgstattuple</title>
...@@ -7,23 +8,28 @@ ...@@ -7,23 +8,28 @@
</indexterm> </indexterm>
<para> <para>
<literal>pgstattuple</literal> modules provides various functions to obtain The <filename>pgstattuple</filename> module provides various functions to
tuple statistics. obtain tuple-level statistics.
</para> </para>
<sect2> <sect2>
<title>Functions</title> <title>Functions</title>
<itemizedlist> <variablelist>
<varlistentry>
<term>
<function>pgstattuple(text) returns record</>
</term>
<listitem> <listitem>
<para> <para>
<literal>pgstattuple()</literal> returns the relation length, percentage <function>pgstattuple</function> returns a relation's physical length,
of the "dead" tuples of a relation and other info. This may help users to percentage of <quote>dead</> tuples, and other info. This may help users
determine whether vacuum is necessary or not. Here is an example session: to determine whether vacuum is necessary or not. The argument is the
target relation's name (optionally schema-qualified).
For example:
</para> </para>
<programlisting> <programlisting>
test=> \x
Expanded display is on.
test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc'); test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc');
-[ RECORD 1 ]------+------- -[ RECORD 1 ]------+-------
table_len | 458752 table_len | 458752
...@@ -36,85 +42,110 @@ dead_tuple_percent | 0.69 ...@@ -36,85 +42,110 @@ dead_tuple_percent | 0.69
free_space | 8932 free_space | 8932
free_percent | 1.95 free_percent | 1.95
</programlisting> </programlisting>
<para> <para>
Here are explanations for each column: The output columns are:
</para> </para>
<table> <table>
<title><literal>pgstattuple()</literal> column descriptions</title> <title><function>pgstattuple</function> output columns</title>
<tgroup cols="2"> <tgroup cols="3">
<thead> <thead>
<row> <row>
<entry>Column</entry> <entry>Column</entry>
<entry>Type</entry>
<entry>Description</entry> <entry>Description</entry>
</row> </row>
</thead> </thead>
<tbody> <tbody>
<row> <row>
<entry>table_len</entry> <entry><structfield>table_len</structfield></entry>
<entry>physical relation length in bytes</entry> <entry><type>bigint</type></entry>
<entry>Physical relation length in bytes</entry>
</row>
<row>
<entry><structfield>tuple_count</structfield></entry>
<entry><type>bigint</type></entry>
<entry>Number of live tuples</entry>
</row> </row>
<row> <row>
<entry>tuple_count</entry> <entry><structfield>tuple_len</structfield></entry>
<entry>number of live tuples</entry> <entry><type>bigint</type></entry>
<entry>Total length of live tuples in bytes</entry>
</row> </row>
<row> <row>
<entry>tuple_len</entry> <entry><structfield>tuple_percent</structfield></entry>
<entry>total tuples length in bytes</entry> <entry><type>float8</type></entry>
<entry>Percentage of live tuples</entry>
</row> </row>
<row> <row>
<entry>tuple_percent</entry> <entry><structfield>dead_tuple_count</structfield></entry>
<entry>live tuples in %</entry> <entry><type>bigint</type></entry>
<entry>Number of dead tuples</entry>
</row> </row>
<row> <row>
<entry>dead_tuple_len</entry> <entry><structfield>dead_tuple_len</structfield></entry>
<entry>total dead tuples length in bytes</entry> <entry><type>bigint</type></entry>
<entry>Total length of dead tuples in bytes</entry>
</row> </row>
<row> <row>
<entry>dead_tuple_percent</entry> <entry><structfield>dead_tuple_percent</structfield></entry>
<entry>dead tuples in %</entry> <entry><type>float8</type></entry>
<entry>Percentage of dead tuples</entry>
</row> </row>
<row> <row>
<entry>free_space</entry> <entry><structfield>free_space</structfield></entry>
<entry>free space in bytes</entry> <entry><type>bigint</type></entry>
<entry>Total free space in bytes</entry>
</row> </row>
<row> <row>
<entry>free_percent</entry> <entry><structfield>free_percent</structfield></entry>
<entry>free space in %</entry> <entry><type>float8</type></entry>
<entry>Percentage of free space</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
<para> <para>
<note> <function>pgstattuple</function> acquires only a read lock on the
<para> relation. So the results do not reflect an instantaneous snapshot;
<literal>pgstattuple</literal> acquires only a read lock on the relation. So concurrent updates will affect them.
concurrent update may affect the result.
</para> </para>
</note>
<note>
<para> <para>
<literal>pgstattuple</literal> judges a tuple is "dead" if HeapTupleSatisfiesNow() <function>pgstattuple</function> judges a tuple is <quote>dead</> if
returns false. <function>HeapTupleSatisfiesNow</> returns false.
</para>
</note>
</para> </para>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>pgstattuple(oid) returns record</>
</term>
<listitem> <listitem>
<para> <para>
<literal>pg_relpages()</literal> returns the number of pages in the relation. This is the same as <function>pgstattuple(text)</function>, except
that the target relation is specified by OID.
</para> </para>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term>
<function>pgstatindex(text) returns record</>
</term>
<listitem> <listitem>
<para> <para>
<literal>pgstatindex()</literal> returns an array showing the information about an index: <function>pgstatindex</function> returns a record showing information
about a btree index. For example:
</para> </para>
<programlisting> <programlisting>
test=> \x
Expanded display is on.
test=> SELECT * FROM pgstatindex('pg_cast_oid_index'); test=> SELECT * FROM pgstatindex('pg_cast_oid_index');
-[ RECORD 1 ]------+------ -[ RECORD 1 ]------+------
version | 2 version | 2
...@@ -128,31 +159,116 @@ deleted_pages | 0 ...@@ -128,31 +159,116 @@ deleted_pages | 0
avg_leaf_density | 50.27 avg_leaf_density | 50.27
leaf_fragmentation | 0 leaf_fragmentation | 0
</programlisting> </programlisting>
<para>
The output columns are:
</para>
<table>
<title><function>pgstatindex</function> output columns</title>
<tgroup cols="3">
<thead>
<row>
<entry>Column</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>version</structfield></entry>
<entry><type>integer</type></entry>
<entry>Btree version number</entry>
</row>
<row>
<entry><structfield>tree_level</structfield></entry>
<entry><type>integer</type></entry>
<entry>Tree level of the root page</entry>
</row>
<row>
<entry><structfield>index_size</structfield></entry>
<entry><type>integer</type></entry>
<entry>Total number of pages in index</entry>
</row>
<row>
<entry><structfield>root_block_no</structfield></entry>
<entry><type>integer</type></entry>
<entry>Location of root block</entry>
</row>
<row>
<entry><structfield>internal_pages</structfield></entry>
<entry><type>integer</type></entry>
<entry>Number of <quote>internal</> (upper-level) pages</entry>
</row>
<row>
<entry><structfield>leaf_pages</structfield></entry>
<entry><type>integer</type></entry>
<entry>Number of leaf pages</entry>
</row>
<row>
<entry><structfield>empty_pages</structfield></entry>
<entry><type>integer</type></entry>
<entry>Number of empty pages</entry>
</row>
<row>
<entry><structfield>deleted_pages</structfield></entry>
<entry><type>integer</type></entry>
<entry>Number of deleted pages</entry>
</row>
<row>
<entry><structfield>avg_leaf_density</structfield></entry>
<entry><type>float8</type></entry>
<entry>Average density of leaf pages</entry>
</row>
<row>
<entry><structfield>leaf_fragmentation</structfield></entry>
<entry><type>float8</type></entry>
<entry>Leaf page fragmentation</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
As with <function>pgstattuple</>, the results are accumulated
page-by-page, and should not be expected to represent an
instantaneous snapshot of the whole index.
</para>
</listitem> </listitem>
</itemizedlist> </varlistentry>
</sect2>
<sect2> <varlistentry>
<title>Usage</title> <term>
<function>pg_relpages(text) returns integer</>
</term>
<listitem>
<para> <para>
<literal>pgstattuple</literal> may be called as a relation function and is <function>pg_relpages</function> returns the number of pages in the
defined as follows: relation.
</para> </para>
<programlisting> </listitem>
CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type </varlistentry>
AS 'MODULE_PATHNAME', 'pgstattuple' </variablelist>
LANGUAGE C STRICT; </sect2>
<sect2>
<title>Author</title>
CREATE OR REPLACE FUNCTION pgstattuple(oid) RETURNS pgstattuple_type
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
LANGUAGE C STRICT;
</programlisting>
<para> <para>
The argument is the relation name (optionally it may be qualified) Tatsuo Ishii
or the OID of the relation. Note that pgstattuple only returns
one row.
</para> </para>
</sect2> </sect2>
</sect1> </sect1>
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment