-
Notifications
You must be signed in to change notification settings - Fork 196
Database
spacewalk-sql --select-mode - <<<"SELECT pid, age(clock_timestamp(), query_start), usename, query FROM pg_stat_activity WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' ORDER BY query_start DESC;"
To continuously log active queries to a file, use:
while sleep 1; do spacewalk-sql --select-mode - <<<"SELECT pid, age(clock_timestamp(), query_start), usename, query FROM pg_stat_activity WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' ORDER BY query_start DESC;" | tee -a /tmp/query.log; done
Add log_min_duration_statement to the configuration file and reload it:
echo "log_min_duration_statement = 1000" >> /var/lib/pgsql/data/postgresql.conf
spacewalk-sql --select-mode - <<<"SELECT pg_reload_conf();"
Queries taking longer than 1 second will appear in logs with their durations. To check:
tail -f /var/lib/pgsql/data/log/`ls -t /var/lib/pgsql/data/log/ | head -1`
A very nice tool to get a visual, browseable representation of a query plan is PEV.
Easiest way to use it is:
- prepare a file with the query with an
EXPLAIN
preamble:
cat >explain.sql <<EOF
EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)
SELECT ...;
EOF
- run the query via
psql
to capure the output in JSON format:
export PGUSER=`grep -oP "db_user ?= ?\K.*" /etc/rhn/rhn.conf`
export PGPASSWORD=`grep -oP "db_password ?= ?\K.*" /etc/rhn/rhn.conf`
export PGDATABASE=`grep -oP "db_name ?= ?\K.*" /etc/rhn/rhn.conf`
psql --quiet --no-align --tuples-only --file=explain.sql > explain.json
- drag
explain.json
into
Copy and paste:
date
printf "\n\n\n**** DATABASE SIZES\n"
du -h /var/lib/pgsql/data
printf "\n\n\n**** TABLE SIZES\n"
spacewalk-sql --select-mode - <<<"
WITH table_sizes AS (
SELECT CAST(relname AS TEXT) AS table_name,
pg_size_pretty(pg_total_relation_size(C.oid)) AS size,
pg_total_relation_size(C.oid) AS ordering
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind <> 'i'
AND nspname !~ '^pg_toast'
ORDER BY ordering DESC
LIMIT 20
),
total_size AS (
SELECT CAST('**TOTAL**' AS TEXT) as table_name,
pg_size_pretty(CAST(SUM(pg_total_relation_size(C.oid)) AS BIGINT)) AS size,
-1 AS ordering
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind <> 'i'
AND nspname !~ '^pg_toast'
),
all_sizes AS (
SELECT * FROM table_sizes UNION ALL (SELECT * FROM total_size)
)
SELECT table_name, size
FROM all_sizes
ORDER BY ordering DESC;
"
There are different ways to get database dumps:
-
pg_dump
: creates a big SQL file that can be run to re-create the DB. This is a compact representation and it can be restored on any later Postgres version, so it's ideal for data analysis. Copy and paste:
mkdir /tmp/backup
chown postgres:postgres /tmp/backup
chmod 700 /tmp/backup
su - postgres -c "pg_dump --create `grep -oP "db_name ?= ?\K.*" /etc/rhn/rhn.conf` | gzip > /tmp/backup/pg_dump.gz"
-
pg_basebackup
throughsmdba
: creates copies of internal PostgreSQL files that can be used as-is. It is less compact thanpg_dump
, it requires the same PostgreSQL version but it preserves some lower level properties, like previous versions of rows, stale space in tables, etc. It is thus more useful in case of performance issues. Moreover many users already usesmdba
for their own backup purposes, so it might be easier to obtain one.
mkdir /tmp/backup
chown postgres:postgres /tmp/backup
chmod 700 /tmp/backup
smdba backup-hot --enable=on --backup-dir=/tmp/backup
smdba backup-hot --enable=off
-
tar
of the data directory with the service down. Simplest, closest to reality, requires downtime.
rcpostgresql stop
tar czvf /tmp/raw_copy.tar.gz /var/lib/pgsql
Create a server with the matching version (eg. using sumaform and stop all services:
spacewalk-service stop
rcsalt-master stop
Then take a look at the dump and see who the main user is (in this example uyuni
):
zless pg_dump.gz
...
ALTER SCHEMA logging OWNER TO uyuni;
...
Create that user with a password (susemanager
in the example), and re-create the destination database ('susemanager' in the example, which is sumaform's default):
su - postgres
psql
CREATE USER susemanager WITH ENCRYPTED PASSWORD 'susemanager';
ALTER ROLE susemanager superuser;
DROP DATABASE susemanager;
CREATE DATABASE susemanager;
\q
Restore the dump to the destination database ('susemanager' in the example):
gzip -d -c /tmp/pg_dump.gz | psql susemanager --set ON_ERROR_STOP=on
BIG DUMP NOTE: if your dump is in the gigabytes of size, copying it to the server and decompressing it might be very slow and require a lot of disk space. In those cases it is more practical to do the decompression on your host with pigz
, which decompresses gzipped files using multiple cores/threads, and transfer the result to a socket to be fed directly into psql
.
On the destination server run: nc -l 8123 | psql susemanager --set ON_ERROR_STOP=on
(nc
comes from the netcat-openbsd
package and waits for data on port 8123. More about netcat)
On your host run: unpigz <pg_dump.gz | nc -N server.tf.local 8123
(unpigz
comes from the pigz
package and decompresses gzipped files using multiple cores/threads. More about pigz)
You can omit the --set ON_ERROR_STOP=on
if you are OK with a non-perfect restore (eg. for data analysis purposes you might not want to stop the process if pl/tcl is missing).
Now change all registered users' passwords to admin
and all email addresses to a dummy address, otherwise the user will get bombed with error emails.
psql susemanager
BEGIN;
UPDATE web_contact set password='$1$IrobqEPV$9lT.npWHmOezFreAJg8Dw/';
UPDATE web_user_personal_info set email = '[email protected]';
COMMIT;
SELECT
wc.login,
string_agg(g.name, ', ') AS groups
FROM web_contact wc
JOIN rhnUserGroupMembers gm ON gm.user_id = wc.id
JOIN rhnUserGroup g ON g.id = gm.user_group_id
GROUP BY login
ORDER BY login;
\q
Note usernames if you want to log in later.
If you need to use the Web UI, adjust /etc/rhn/rhn.conf
connection parameters and /var/lib/pgsql/data/pg_hba.conf
according to the possibly changed username, password and database name. Example:
vim /etc/rhn/rhn.conf
...
db_backend = postgresql
db_user = susemanager
db_password = susemanager
db_name = susemanager
db_host = localhost
db_port = 5432
# check pg_hba.conf. There should be lines like the following (username is the third column):
vim /var/lib/pgsql/data/pg_hba.conf
local susemanager susemanager md5
host susemanager susemanager 127.0.0.1/8 md5
host susemanager susemanager ::1/128 md5
...
rcpostgresql restart
rcsalt-master start
spacewalk-service start
spacewalk-service stop
rcsalt-master stop
rcpostgresql stop
# move away existing data
mv /var/lib/pgsql/data /var/lib/pgsql/data_orig
mkdir /var/lib/pgsql/data
# replace with data from archive
cd /var/lib/pgsql/data
tar xvf ~/base.tar.gz
chown -R postgres:postgres /var/lib/pgsql/data
chmod -R 0700 /var/lib/pgsql/data
# replace base tuning configuration, hardware is likely different
cp /var/lib/pgsql/data/postgresql.conf /var/lib/pgsql/data/postgresql.orig
smdba system-check autotuning --max_connections=50
# allow access from other hosts
echo listen_addresses = \'*\' >> /var/lib/pgsql/data/postgresql.conf
echo host all all 0.0.0.0/0 md5 >> /var/lib/pgsql/data/pg_hba.conf
rcpostgresql start
# list Postgres users and change the password to 'susemanager'
su -l postgres
psql
\du
# there should be two roles: "postgres" and a user one (typically "susemanager")
# from here on, it is assumed "susemanager" is the user name. If it is not, please adapt
# following instructions accordingly
ALTER USER susemanager WITH ENCRYPTED PASSWORD 'susemanager';
ALTER ROLE susemanager superuser;
\q
# check pg_hba.conf. There should be lines like the following (username is the third column):
# local susemanager susemanager md5
# host susemanager susemanager 127.0.0.1/8 md5
# host susemanager susemanager ::1/128 md5
# ...
vim /var/lib/pgsql/data/pg_hba.conf
# change all SUSE Manager users' passwords to 'admin'
# and all email addresses. Otherwise the user will get bombed with error emails
PGPASSWORD=susemanager psql -h localhost -d susemanager -U susemanager
BEGIN;
UPDATE web_contact set password='$1$IrobqEPV$9lT.npWHmOezFreAJg8Dw/';
UPDATE web_user_personal_info set email = '[email protected]';
COMMIT;
SELECT
wc.login,
string_agg(g.name, ', ') AS groups
FROM web_contact wc
JOIN rhnUserGroupMembers gm ON gm.user_id = wc.id
JOIN rhnUserGroup g ON g.id = gm.user_group_id
GROUP BY login
ORDER BY login;
\q
exit
# double check that database credentials are correct (in particular the username)
vim /etc/rhn/rhn.conf
rcsalt-master start
spacewalk-service start
BIG DUMP NOTE: if your dump is in the gigabytes of size, copying it to the server and decompressing it might be very slow and require a lot of disk space. In those cases it is more practical to do the decompression on your host with pigz
, which decompresses gzipped files using multiple cores/threads, and transfer the result to a socket to be fed directly into psql
.
On the destination server run: nc -l 8123 | tar -xv
(nc
comes from the netcat-openbsd
package and waits for data on port 8123. More about netcat)
On your host run: unpigz <pg_dump.gz | nc -N server.tf.local 8123
(unpigz
comes from the pigz
package and decompresses gzipped files using multiple cores/threads. More about pigz)