You are on page 1of 56

Important Queries

Shankarnag
EnterpriseDB

INDEX

Autovacuum
Vacuum
- 5
System Queries - 6
CTID
- 40
Func & Triggers - 47

Autovacuum Demo on single


table

create table :create table test_auto(id integer primary key,name


varchar(10));

Assign the autovacuum settings :ALTER table test_auto SET


(autovacuum_vacuum_threshold=50,
autovacuum_analyze_threshold=50);

Inset rows in the table :insert into test_auto values (generate_series(2,100000));

delete rows :delete from test_auto where a% 2=0;

Now check the autovacuum is enabled on single table using


below command or log files
select last_autovacuum,last_autoanalyze from
pg_stat_all_tables where relname='test_auto';
\d+ <tablename>

disable auto vacuum :ALTER TABLE sometable SET (


autovacuum_enabled = false, toast.autovacuum_enabled
= false
);

enable auto vacuum :ALTER TABLE sometable SET (


autovacuum_enabled = true, toast.autovacuum_enabled
= true
);

Vacuum Demo :
create table trunc( id int);
insert into trunc VALUES (generate_series(1,10));
select ctid,id from trunc ;
delete from trunc where id % 2=0;
select ctid,id from trunc ;
VACUUM verbose trunc ;
insert into trunc VALUES (2);
postgres=# select ctid,id from trunc ;

System Queries
Find the number of live rows vs dead
rows of a table :select relname
as "Table",
n_live_tup
as "Live tuples",
n_dead_tup
as "Dead tuples"
from pg_stat_user_tables
where relname = 'my_table';

Finding the read activity


statistics of tables in a database
select schemaname as "Schema
Name" ,
relname
as "Table Name",
seq_tup_read+idx_tup_fetch as "
no.of reads" from pg_stat_all_tables
order by seq_tup_read+idx_tup_fetch;

Finding the write activity


statistics of tables in a database::
select schemaname as " Schema
Name",
relname
as "Table Name,
n_tup_ins+n_tup_upd+n_tup_del
as "no.of writes" from
pg_stat_all_tables
order by
n_tup_ins+n_tup_upd+n_tup_del;

Find out the I/O statistics of a


table
select relname
as "Table",
heap_blks_read as "Heap from disc",
heap_blks_hit as "Heap from cache",
idx_blks_read as "Index from disc",
idx_blks_hit as "Index from cache",
toast_blks_read as "Toast from disc",
toast_blks_hit as "Toast from cache",
tidx_blks_read as "Toast index disc",
tidx_blks_hit as "Toast index cache"
from pg_statio_user_tables
where relname = 'my_table';

Find the size of all databases in


a cluster::
select datname as "Database name,
pg_size_pretty(pg_database_size(dat
name)) as "Size of each database"
from pg_database;

Find out the index statistics in a


database
select relname as "Tablename",
indexrelname as "Index name",
idx_scan as "Index lookups",
idx_tup_read as "Index entries",
idx_tup_fetch as "Tuples fetched
via index"
from pg_stat_user_indexes
order by relname,indexrelname;

Finding the lock statistics in a


database
select pid as "Process id,
mode,
current_query as " Sql query"
from pg_locks,pg_stat_activity
where granted=false and
locktype='transactionid' and
pid=procpid order by pid,granted;

Finding the sizes of indexes in a


database
select relname as "Table name",
indexrelname as " Index
name",
pg_size_pretty( pg_relation_size(
indexrelid ) ) as "Size"
from pg_stat_all_indexes
where schemaname = 'public' and
relname='users'
order by pg_relation_size( indexrelid )
desc;

Finding the Database statistics


in a cluster
Select

datname
as "Database",
numbackends
as "Backends",
xact_commit
as "Xact Committed",
xact_rollback
as "Xact Rolled Back",
blks_read
as "Blocks Read",
blks_hit
as "Blocks Hit",
(pg_database_size(datid) / 1024)::int as "Size (KB)"
FROM pg_stat_database db
WHERE UPPER(db.datname) != 'TEMPLATE0' AND
UPPER(db.datname) != 'TEMPLATE1'
ORDER BY "Database";

Finding the number of users


connected to each Database in
a cluster

SELECT COUNT(datid) as "Count",


datconnlimit "Connection
Limit per Database",
d.datname as "Database
Name"
FROM pg_database d LEFT JOIN
pg_stat_activity s ON (s.datid =
d.oid) GROUP BY 2,3 ORDER BY
d.datname;

Size of each table inside the Database


on PostgreSQL 8.4 on-words::
SELECT tablename as " Table Name",
pg_size_pretty(pg_total_relation_size(CAST(tablena
me AS TEXT))) as Total size of table",
pg_size_pretty((pg_total_relation_size(CAST(tablenam
e AS TEXT)) - pg_relation_size(CAST(tablename AS
TEXT)))) as "Index size
FROM pg_tables
WHERE schemaname != 'pg_catalog' AND
schemaname != 'information_schema' ORDER BY
pg_total_relation_size(CAST(tablename AS TEXT));

List of tables in a Database:


SELECT relname as "Table Name
FROM pg_class
WHERE relname !~ '^(pg_|sql_)'
AND relkind = 'r';

List sequences
SELECT relname as " Sequence
Name
FROM pg_class
WHERE relkind = 'S' AND
relnamespace IN ( SELECT oid FROM
pg_namespace WHERE nspname
NOT LIKE 'pg_%' AND nspname !=
'information_schema' );

List Triggers of a table:


SELECT trg.tgname as "Trigger_name"
FROM pg_trigger trg, pg_class tbl
WHERE trg.tgrelid = tbl.oid AND
tbl.relname = 'newtable';

Which tables are being updated


the most and looking for vacuum ::
select relname, /* pg_size_pretty( pg_relation_size( relid ) ) as
table_size,
pg_size_pretty( pg_total_relation_size( relid ) ) as table_total_size,
*/
n_tup_upd, n_tup_hot_upd, n_live_tup, n_dead_tup,
last_vacuum::date, last_autovacuum::date, last_analyze::date,
last_autoanalyze::date
from pg_stat_all_tables
where relid in (select oid from pg_class
where relnamespace not in
(select oid from pg_namespace
where nspname in ('information_schema', 'pg_catalog',
'pg_toast', 'edbhc' ) ) )
order by n_tup_upd desc, schemaname, relname;

It gives index scanned less


than 200 times and is not
unique.
SELECT idstat.relname AS table_name, indexrelname AS index_name,

idstat.idx_scan AS times_used,

pg_size_pretty(pg_relation_size(idstat.relname)) AS table_size,
pg_size_pretty(pg_relation_size(indexrelname)) AS index_size,

n_tup_upd + n_tup_ins + n_tup_del as num_writes,

indexdef AS definition

FROM pg_stat_user_indexes AS idstat JOIN pg_indexes ON indexrelname = indexname

JOIN pg_stat_user_tables AS tabstat ON idstat.relname = tabstat.relname

WHERE idstat.idx_scan < 200

AND indexdef !~* 'unique'

ORDER BY idstat.relname, indexrelname;

Size of each schema in a


Database::
SELECT nspname, sum(relpages * cast( 8192 AS bigint ))
as "table size", sum( ( select sum(relpages) from
pg_class i, pg_index idx where i.oid = idx.indexrelid
and t.oid=idx.indrelid ) ) * cast( 8192 AS bigint ) as
"index size", sum ( relpages * cast( 8192 AS bigint ) +
( select sum(relpages) from pg_class i, pg_index idx
where i.oid = idx.indexrelid and t.oid=idx.indrelid ) *
cast( 8192 AS bigint ) ) as "size" FROM pg_class t,
pg_namespace WHERE relnamespace =
pg_namespace.oid and pg_namespace.nspname not
like 'pg_%' and pg_namespace.nspname !=
'information_schema' and relkind = 'r' group by
nspname;

Find out how many pages and


tuples are used by a table
select relname
as "table",
reltuples
as "number of
tuples",
relpages
as "number of 8kb
pages"
from pg_class
where relname = 'table';

Find out the Primary key tables


in a database
SELECT tablename FROM pg_tables
WHERE tablename IN (SELECT
r.relname FROM pg_class r,
pg_constraint c WHERE r.oid =
c.conrelid AND c.contype = 'p') AND
schemaname = 'public';

Which user PID is locking on


which transaction process
select bl.pid as blocked_pid, a.usename as
blocked_user,kl.pid as blocking_pid, ka.usename
as blocking_user, a.current_query as
blocked_statement from pg_catalog.pg_locks bl
join pg_catalog.pg_stat_activity a on bl.pid =
a.procpid
join pg_catalog.pg_locks kl
join pg_catalog.pg_stat_activity ka on kl.pid =
ka.procpid on bl.transactionid = kl.transactionid
and bl.pid != kl.pid
where not bl.granted;

Checking the user permissions


SELECT relname as "Relation", relacl
as "Access permissions" FROM
pg_classWHERE relkind IN ('r', 'v',
'S') AND relname !~ '^pg_' ORDER
BY relname;

Retrieving the name of the user associated with the


current postgres backend.

postgres=# select getpgusername();


getpgusername
--------------postgres
Retrieving the client encoding of the server

postgres=# select pg_client_encoding();


pg_client_encoding
-------------------UTF8

SIGHUP signal to the postmaster, causing the


configuration files to be reloaded by all server processes.
postgres=# Select pg_reload_conf();
pg_reload_conf
---------------t

pg_rotate_logfile:: pg_rotate_logfile signals the log-file


manager to switch to a new output file immediately and it
works only when logtype is stderr.
postgres=# select pg_ls_dir('pg_log');
pg_ls_dir
-----------------------------------------postgresql-2010-10-22_221941.log
postgresql-2010-10-23_000000.log
postgresql-2010-10-23_011320.log
postgresql-2010-10-24_000000.log

postgres=# select pg_rotate_logfile();


pg_rotate_logfile
------------------t
(1 row)

postgres=# select pg_ls_dir('pg_log');


pg_ls_dir
-----------------------------------------postgresql-2010-10-22_221941.log
postgresql-2010-10-23_000000.log
postgresql-2010-10-23_011320.log

5. pg_ls_dir -- It shows content of given


directory except the special entries . and ...
(it is treated as relative to $PGDATA). it is not
possible (or i dont know how to) to go to
another directories than $PGDATA.
postgres=# select pg_ls_dir('pg_xlog');
pg_ls_dir
-------------------------000000010000000000000003
000000010000000000000004
000000010000000000000005
archive_status
(4 rows)

6. pg_sleep It makes the current sessions process sleep until


seconds seconds have elapsed.

Ex:

postgres=# SELECT CURRENT_TIMESTAMP; SELECT pg_sleep(60); SELECT


CURRENT_TIMESTAMP;
now
---------------------------------2010-10-24 13:51:54.158547+05:30
(1 row)

pg_sleep
---------(1 row)

now
---------------------------------2010-10-24 13:52:54.186517+05:30
(1 row)

pg_char_to_encoding convert from one from of


encoding to another

EX:- How do I convert a database in the ASCII format into one of


the UTF-8 format?

template1=# create database test with encoding='SQL_ASCII';


CREATE DATABASE
template1=# \connect test
You are now connected to database "test".
test=# create table a (x text);
CREATE TABLE
test=# insert into a values ('');
INSERT 33304378 1
test=# select * from a;
x
-
(1 row)
Contd :

test=# update pg_database set encoding =


pg_catalog.pg_char_to_encoding('UTF8') where datname='test';
UPDATE 1
test=# select * from a;
x
-
(1 row)

test=# \connect template1


You are now connected to database "template1".
template1=# \connect test
You are now connected to database "test".
test=# select * from a;
x
-
(1 row)

pg_postmaster_start_time Retrieves the postmaster start time

postgres=# select pg_postmaster_start_time();


pg_postmaster_start_time
------------------------------2010-09-01 11:39:36.472834-04
(1 row)

pg_switch_xlog Generates manual switch on the current


transaction log in the database.

postgres=# select pg_xlogfile_name(pg_current_xlog_location());


pg_xlogfile_name
-------------------------000000010000000000000009
(1 row)

postgres=# select pg_switch_xlog();


pg_switch_xlog
---------------0/A000000
(1 row)
postgres=# select pg_xlogfile_name(pg_current_xlog_insert_location());
pg_xlogfile_name
-------------------------00000001000000000000000A
(1 row)

pg_current_xlog_location -- displays the current transaction


log write location

postgres=# select pg_current_xlog_location();


pg_current_xlog_location
-------------------------0/8000064
(1 row)

pg_xlogfile_name extract the transaction log file name.

postgres=# select pg_xlogfile_name('0/8000064');


pg_xlogfile_name
-------------------------000000010000000000000008
(1 row)

pg_current_xlog_insert_location
Retrieves the current transaction log
insertion file name.
postgres=# select
pg_current_xlog_insert_location();
pg_current_xlog_insert_location
--------------------------------0/A000064

pg_stat_get_numscans -- It shows the number of sequential scans occured on


a table

syntax: select pg_stat_get_numscans(oid);

postgres=# select relfilenode,relname from pg_class where relname='test';


relfilenode | relname
-------------+--------18328 | test
(1 row)

postgres=# select pg_stat_get_numscans(18328);


pg_stat_get_numscans
---------------------4
(or)

postgres=# select relname,seq_scan from pg_Stat_user_tables;


relname
| seq_scan
--------------------+---------sl_table
|
0
sl_setsync
|
0
test
|
4

pg_stat_get_live_tuples -- Retrieves the number of live rows in a table

syntax: select pg_stat_get_live_tuples(oid);

postgres=# select relfilenode,relname from pg_class where relname='test';


relfilenode | relname
-------------+--------18328 | test
(1 row)

postgres=# select pg_stat_get_live_tuples(18328);


pg_stat_get_live_tuples
------------------------10
(1 row)

pg_stat_get_dead_tuples -- Retrieves the dead rows in


a table.

Syntax: select pg_stat_get_dead_tuples(oid);

postgres=# select pg_stat_get_dead_tuples(18328);


pg_stat_get_dead_tuples
------------------------0
(1 row)

CTID Demo

postgres=# select pg_relation_size('emails');


pg_relation_size
-----------------8192
postgres=# select ctid,* from emails;
ctid |
email
--------+-------------------------------(0,1) | 1995liufang@sima.com
(0,2) | molly.nguyen@tenethealth.com
(0,3) | edwyn0407@blackberry.net
(0,4) | kathryn.canete@tenethealth.com
(0,5) | akanwo@yahoo.com
(0,6) | dnh@a.com
(0,7) | cteng1230@gmail.com
(0,8) | ajuvenillehood@aol.com
(0,9) | derkmau@gmail.com
(0,10) | gbarnes@remax.net
(10 rows)

postgres=# select * from emails where ctid='(0,8)';


email
-----------------------ajuvenillehood@aol.com
(1 row)
postgres=# delete from email where ctid < 5;
ERROR: relation "email" does not exist
postgres=# delete from emails where ctid < 5;
ERROR: operator does not exist: tid < integer
LINE 1: delete from emails where ctid < 5;
^
HINT: No operator matches the given name and argument type(s). You
might need to add explicit type casts.
postgres=# delete from emails where email='ajuvenillehood@aol.com';
DELETE 1

postgres=# select ctid,* from emails;


ctid |
email
--------+-------------------------------(0,1) | 1995liufang@sima.com
(0,2) | molly.nguyen@tenethealth.com
(0,3) | edwyn0407@blackberry.net
(0,4) | kathryn.canete@tenethealth.com
(0,5) | akanwo@yahoo.com
(0,6) | dnh@a.com
(0,7) | cteng1230@gmail.com
(0,9) | derkmau@gmail.com
(0,10) | gbarnes@remax.net
(9 rows)
postgres=# select * from emails where ctid='(0,8)';
email
------(0 rows)

postgres=# \d cluster
Did not find any relation named "cluster".
postgres=# \h cluster
Command:
CLUSTER
Description: cluster a table according to an index
Syntax:
CLUSTER tablename [ USING indexname ]
CLUSTER
postgres=# cluster emails;
ERROR: there is no previously clustered index for table "emails"
postgres=# VACUUM ANALYZE emails;
VACUUM
postgres=# select * from emails where ctid='(0,8)';
email
------(0 rows)

postgres=# select ctid,* from emails;


ctid |
email
--------+-------------------------------(0,1) | 1995liufang@sima.com
(0,2) | molly.nguyen@tenethealth.com
(0,3) | edwyn0407@blackberry.net
(0,4) | kathryn.canete@tenethealth.com
(0,5) | akanwo@yahoo.com
(0,6) | dnh@a.com
(0,7) | cteng1230@gmail.com
(0,9) | derkmau@gmail.com
(0,10) | gbarnes@remax.net
(9 rows)

postgres=# select ctid,xmin,xmax,* from emails;


ctid | xmin | xmax |
email
--------+------+------+-------------------------------(0,1) | 575 | 0 | 1995liufang@sima.com
(0,2) | 575 | 0 | molly.nguyen@tenethealth.com
(0,3) | 575 | 0 | edwyn0407@blackberry.net
(0,4) | 575 | 0 | kathryn.canete@tenethealth.com
(0,5) | 575 | 0 | akanwo@yahoo.com
(0,6) | 575 | 0 | dnh@a.com
(0,7) | 575 | 0 | cteng1230@gmail.com
(0,9) | 575 | 0 | derkmau@gmail.com
(0,10) | 575 | 0 | gbarnes@remax.net
(9 rows)

FUNCTIONS

create or replace function sum_val(i


numeric, z numeric) returns numeric
as
$$
begin
return i+z;
end;
$$ language plpgsql;

create or replace function differ(x numeric, y numeric) returns


void as
$$
declare
d numeric;
begin
d:=x-y;
raise notice 'Difference is: %',d;
return;
end;
$$ language plpgsql;
select differ(10,5);

create or replace function dis_cus(c_id numeric) returns void as


$$
declare
rec RECORD;
begin
select into rec * from customer where custid=c_id;
if found then
raise notice 'Customer Name: %', rec.custname;
raise notice 'Account No: %', rec.accountid;
else
raise notice 'No Data';
end if;
return;
end;$$ language plpgsql;
select differ(10,5);

create or replace function dis() returns void as


$$
declare
rec numeric;
begin
rec:=0;
while rec<=10 loop
raise notice '%',rec;
rec:=rec+1;
end loop;
return;
end;$$ language plpgsql;

create or replace function dis1() returns void as


$$
declare
rec numeric;
begin
for rec in 0..10 by 2 loop
raise notice '%',rec;
end loop;
return;
end;$$ language plpgsql;

create or replace function dis_cus() returns void as


$$
declare
rec record;
begin
for rec in select*from customer loop
raise notice 'Customer Name: %', rec.custname;
raise notice 'Account No: %', rec.accountid;
end loop;
return;
end;$$ language plpgsql;

create or replace function dis_cus() returns void as


$$
declare
cur CURSOR for select*from customer;
rec RECORD;
begin
open cur;
fetch cur into rec;
while found loop
raise notice 'Customer Name: %', rec.custname;
raise notice 'Account No: %', rec.accountid;
fetch cur into rec;
end loop;
close cur;
return;
end;$$ language plpgsql;

atmrep=# create table city(cityid numeric, population


numeric);
CREATE TABLE
atmrep=# create table birth(regid numeric, name varchar,
cityid numeric);
CREATE TABLE
atmrep=# insert into city values(1,0),(2,0);
INSERT 0 2
atmrep=# select*from city;
cityid | population
--------+-----------1|
0
2|
0
(2 rows)
Contd :-

atmrep=# create or replace function trg_ins() returns trigger as


atmrep-# $$
atmrep$# begin
atmrep$# update city set population=population+1 where cityid=NEW.cityid;
atmrep$# return null;
atmrep$# end; $$ language plpgsql;
CREATE FUNCTION
atmrep=# create trigger trg_ins_brth after insert on birth
atmrep-# for each row
atmrep-# execute procedure trg_ins();
CREATE TRIGGER
atmrep=# insert into birth values(101,'Raj',2);
INSERT 0 1
atmrep=# select*from birth;
regid | name | cityid
-------+------+-------101 | Raj |
2
(1 row)
atmrep=# select*from city;