100% found this document useful (1 vote)
187 views

Postgre SQL

PostgreSQL is an open-source object-relational database management system that was developed at the University of California, Berkeley and pioneered many concepts now common in commercial databases. It supports features like complex queries, foreign keys, triggers, updatable views, and transactional integrity. PostgreSQL can also be extended by users through adding new data types, functions, operators, and other elements.

Uploaded by

fernanda vazquez
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
187 views

Postgre SQL

PostgreSQL is an open-source object-relational database management system that was developed at the University of California, Berkeley and pioneered many concepts now common in commercial databases. It supports features like complex queries, foreign keys, triggers, updatable views, and transactional integrity. PostgreSQL can also be extended by users through adding new data types, functions, operators, and other elements.

Uploaded by

fernanda vazquez
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 85

POSTGRESQL

¿Que es PostgreSQL?
PostgreSQL is an object-relational database management system
(ORDBMS) developed at the University of California at Berkeley
Computer Science Department. POSTGRES pioneered many
concepts that only became available in some commercial
database systems much later. PostgreSQL is an open-source
descendant of this original Berkeley code. It supports a large part
of the SQL standard and offers many modern features:
• complex queries
• foreign keys
• triggers
• updatable views
• transactional integrity
• multiversion concurrency control
¿Que es PostgreSQL?
Also, PostgreSQL can be extended by the user in many ways,
for example by adding new
• data types
• functions
• operators
• aggregate functions
• index methods
• procedural languages
Architectural Fundamentals

• Config files
• postgresql.conf PostgreSQL configuration file
• pg_hba.conf PostgreSQL Client Authentication Config
File
• Data Directory PGDATA /var/lib/postgresql/13/main
Specifies the directory to use for data storage. This parameter can only
be set at server start.
• pg_ident.conf PostgreSQL User Name Maps
• Environment Variables
• PATH=/usr/local/pgsql/bin:$PATH
• PGDATA /var/lib/postgresql/13/main
• MANPATH=/usr/local/pgsql/share/man:$MANPATH
Connecting to a Server

Client Middle tier DB Server

Multitier architecture shown


Application RDBMS

TCP/IP
Client or network
Listener Database server
middle tier

configuration files configuration files


Instance & Data Base

Backgroud wal
checkpointer
MEMORY writer writer

logical
autovacuum Stats
replication
launcher collector
launcher

/var/lib/postgresql/13/main
DISK
Database Physical Storage
Traditionally, the configuration and data files used by a database cluster are stored together
within the cluster's data directory, commonly referred to as PGDATA (after the name of the
environment variable that can be used to define it). A common location for PGDATA is
/var/lib/pgsql/data. Multiple clusters, managed by different server instances, can exist on the
same machine.
Contents of PGDATA

Item Description
PG_VERSION A file containing the major version number of PostgreSQL
base Subdirectory containing per-database subdirectories
current_logfiles File recording the log file(s) currently written to by the logging collector
global Subdirectory containing cluster-wide tables, such as pg_database
pg_commit_ts Subdirectory containing transaction commit timestamp data
pg_dynshmem Subdirectory containing files used by the dynamic shared memory subsystem
pg_logical Subdirectory containing status data for logical decoding
Database Physical Storage
Item Description
pg_multixact decoding pg_multixact Subdirectory containing multitransaction status data
(used for shared row locks)
pg_notify Subdirectory containing LISTEN/NOTIFY status data
pg_replslot Subdirectory containing replication slot data
pg_serial Subdirectory containing information about committed serializable transactions
pg_snapshots Subdirectory containing exported snapshots
pg_stat Subdirectory containing permanent files for the statistics subsystem
pg_stat_tmp Subdirectory containing temporary files for the statistics subsystem
pg_subtrans Subdirectory containing subtransaction status data
pg_tblspc Subdirectory containing symbolic links to tablespaces
pg_twophase Subdirectory containing state files for prepared transactions
pg_wal Subdirectory containing WAL (Write Ahead Log) files
pg_xact Subdirectory containing transaction commit status data
postgresql.auto.con A file used for storing configuration parameters that are set by ALTER SYSTEM
f
Database Physical Storage
Item Description
postmaster.opts A file recording the command-line options the server was last started with
postmaster.pid A lock file recording the current postmaster process ID (PID), cluster data
directory path, postmaster start timestamp, port number, Unixdomain socket
directory path (could be empty), first valid listen_address (IP address or *, or
empty if not listening on TCP), and shared memory segment ID (this file is not
present after server shutdown)

For each database in the cluster there is a subdirectory within PGDATA/base, named after the
database's OID in pg_database. This subdirectory is the default location for the database's files;
in particular, its system catalogs are stored there.
createdb
createdb — create a new PostgreSQL database
Synopsis createdb [connection-option...] [option...] [dbname [description]]
Description createdb creates a new PostgreSQL database. Normally, the database user who
executes this command becomes the owner of the new database. However, a different owner
can be specified via the -O option, if the executing user has appropriate privileges. createdb is
a wrapper around the SQL command CREATE DATABASE. There is no effective difference
between creating databases via this utility and via other methods for accessing the server.
Options createdb accepts the following command-line arguments:
dbname Specifies the name of the database to be created. The name must be unique among
all PostgreSQL databases in this cluster. The default is to create a database with the same
name as the current system user.
description Specifies a comment to be associated with the newly created database.
-D tablespace --tablespace=tablespace Specifies the default tablespace for the database.
(This name is processed as a double-quoted identifier.)
createdb
Examples To create the database demo using the default database server:
$ createdb demo T
o create the database demo using the server on host eden, port 5000, using the template0
template database, here is the command-line command and the underlying SQL command:

$ createdb -p 5000 -h eden -T template0 -e demo


CREATE DATABASE demo TEMPLATE template0;
CREATE USER
CREATE USER — define a new database role

Synopsis
CREATE USER name [ [ WITH ] option [ ... ] ] where option can be: SUPERUSER |
NOSUPERUSER | CREATEDB | NOCREATEDB | CREATEROLE | NOCREATEROLE | INHERIT |
NOINHERIT | LOGIN | NOLOGIN | REPLICATION | NOREPLICATION | BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit | [ ENCRYPTED ] PASSWORD 'password' | PASSWORD NULL |
VALID UNTIL 'timestamp' | IN ROLE role_name [, ...] | IN GROUP role_name [, ...] | ROLE
role_name [, ...] | ADMIN role_name [, ...] | USER role_name [, ...] | SYSID uid
CREATE USER
Description CREATE USER is now an alias for CREATE ROLE. The only
difference is that when the command is spelled CREATE USER, LOGIN is
assumed by default, whereas NOLOGIN is assumed when the command
is spelled CREATE ROLE.
Compatibility The CREATE USER statement is a PostgreSQL extension.
The SQL standard leaves the definition of users to the implementation.
CREATE ROLE
CREATE ROLE name [ [ WITH ] option [ ... ] ]
where option can be:
SUPERUSER | NOSUPERUSER | CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE | INHERIT | NOINHERIT |
LOGIN | NOLOGIN | REPLICATION | NOREPLICATION |
BYPASSRLS | NOBYPASSRLS | CONNECTION LIMIT
connlimit | [ ENCRYPTED ] PASSWORD 'password' |
PASSWORD NULL | VALID UNTIL 'timestamp' | IN ROLE
role_name [, ...] | IN GROUP role_name [, ...] | ROLE
role_name [, ...] | ADMIN role_name [, ...] | USER
role_name [, ...] | SYSID uid
CREATE ROLE
CREATE ROLE adds a new role to a PostgreSQL database
cluster. A role is an entity that can own database objects and
have database privileges; a role can be considered a “user”,
a “group”, or both depending on how it is used. Refer to
Chapter 21 and Chapter 20 for information about managing
users and authentication. You must have CREATEROLE
privilege or be a database superuser to use this command.
Note that roles are defined at the database cluster level, and
so are valid in all databases in the cluster
CREATE ROLE
Examples:

Create a role that can log in, but don't give it a password:

CREATE ROLE jonathan LOGIN;


Create a role with a password:

CREATE USER david WITH PASSWORD 'jw8s0F4’;


CREATE USER is the same as CREATE ROLE except that it implies
LOGIN.)

Create a role with a password that is valid until the end of 2021. After
one second has ticked in 2022, the password is no longer valid.

CREATE ROLE miriam WITH LOGIN PASSWORD 'jw8s0F4' VALID UNTIL


‘2022-01-01';
CREATE ROLE
Examples:

Create a role that can create databases and manage roles:

CREATE ROLE admin WITH CREATEDB CREATEROLE;


Assigning Privileges to Roles and Assigning
Roles to Users

Users
Jenny David Rachel

Roles HR_MGR HR_CLERK

Privileges Delete Create Update


employees. Job. employees.

Insert Select
employees. employees.
GRANT
GRANT — define access privileges

Synopsis
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [, ...] | ALL
[ PRIVILEGES ] } ON { [ TABLE ] table_name [, ...] | ALL TABLES IN SCHEMA schema_name [, ...] } TO
role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { SELECT | INSERT | UPDATE | REFERENCES }
( column_name [, ...] ) [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) } ON [ TABLE ] table_name [, ...] TO
role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { USAGE | SELECT | UPDATE } [, ...] | ALL
[ PRIVILEGES ] } ON { SEQUENCE sequence_name [, ...] | ALL SEQUENCES IN SCHEMA schema_name [, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { CREATE | CONNECT | TEMPORARY | TEMP }
[, ...] | ALL [ PRIVILEGES ] } ON DATABASE database_name [, ...] TO role_specification [, ...] [ WITH GRANT
OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON DOMAIN domain_name [, ...] TO role_specification [, ...]
[ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN DATA WRAPPER fdw_name
[, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN
SERVER server_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { EXECUTE | ALL
[ PRIVILEGES ] } ON { { FUNCTION | PROCEDURE | ROUTINE } routine_name [ ( [ [ argmode ] [ arg_name ]
arg_type [, ...] ] ) ] [, ...] | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name [, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON LANGUAGE
lang_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { SELECT | UPDATE } [, ...] |
ALL [ PRIVILEGES ] }
GRANT
GRANT on Roles This variant of the GRANT command grants membership in a role to
one or more other roles. Membership in a role is significant because it conveys the
privileges granted to a role to each of its members. If WITH ADMIN OPTION is specified,
the member can in turn grant membership in the role to others, and revoke
membership in the role as well. Without the admin option, ordinary users cannot do
that. A role is not considered to hold WITH ADMIN OPTION on itself, but it may grant or
revoke membership in itself from a database session where the session user matches
the role. Database superusers can grant or revoke membership in any role to anyone.
Roles having CREATEROLE privilege can grant or revoke membership in any role that is
not a superuser. If GRANTED BY is specified, the grant is recorded as having been done
by the specified role. Only database superusers may use this option, except when it
names the same role executing the command. Unlike the case with privileges,
membership in a role cannot be granted to PUBLIC. Note also that this form of the
command does not allow the noise word GROUP in role_specification.
GRANT
Examples

Grant insert privilege to all users on table films:


GRANT INSERT ON films TO PUBLIC;

Grant all available privileges to user manuel on table employee:


GRANT ALL PRIVILEGES ON employee TO manuel;

Note that while the above will indeed grant all privileges if
executed by a superuser or the owner of kinds, when executed by
someone else it will only grant those permissions for which the
someone else has grant options. Grant membership in role admins
to user joe:

GRANT admins TO joe;


REVOKE
REVOKE — remove access privileges. The REVOKE command revokes previously granted
privileges from one or more roles. The key word PUBLIC refers to the implicitly defined group of
all roles.

Synopsis

REVOKE [ GRANT OPTION FOR ] { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE |


REFERENCES | TRIGGER } [, ...] | ALL [ PRIVILEGES ] } ON { [ TABLE ] table_name [, ...] | ALL
TABLES IN SCHEMA schema_name [, ...] } FROM role_specification [, ...] [ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ] { { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [,
...] ) [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) } ON [ TABLE ] table_name [, ...] FROM
role_specification [, ...] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { { USAGE |
SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON { SEQUENCE sequence_name [, ...] | ALL
SEQUENCES IN SCHEMA schema_name [, ...] } FROM role_specification [, ...] [ CASCADE |
RESTRICT ] REVOKE [ GRANT OPTION FOR ] { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] |
ALL [ PRIVILEGES ] } ON DATABASE database_name [, ...] FROM role_specification [, ...]
[ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON
DOMAIN domain_name [, ...] FROM role_specification [, ...] [ CASCADE | RESTRICT ] REVOKE
[ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN DATA WRAPPER fdw_name [,
...] FROM role_specification [, ...] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] } ON FOREIGN SERVER server_name [, ...] FROM role_specification
REVOKE
Examples:

Revoke insert privilege for the public on table films:


REVOKE INSERT ON films FROM PUBLIC;

Revoke all privileges from user manuel on table employee:


REVOKE ALL PRIVILEGES ON employee FROM manuel;

Note that this actually means “revoke all privileges that I


granted”. Revoke membership in role admins from user joe:
REVOKE admins FROM joe;
Locks
• Prevent multiple sessions from changing the same data at the same
time
• Are automatically obtained at the lowest possible level for a given
statement
• Do not escalate

Transaction 1 Transaction 2

SQL> UPDATE employee SQL> UPDATE employee


2 SET salary=salary+100 2 SET salary=salary*1.1
3 WHERE employee_id=100; 3 WHERE employee_id=100;
Locking Mechanism
• High level of data concurrency:
• Row-level locks for inserts, updates, and deletes
• No locks required for queries (select)
• Automatic queue management
• Locks held until the transaction ends (with
the COMMIT or ROLLBACK operation)

Transaction 1 Transaction 2

SQL> UPDATE employee SQL> UPDATE employee


2 SET salary=salary+100 2 SET salary=salary*1.1
3 WHERE employee_id=100; 3 WHERE employee_id=101;
Locking

• Explicit Locking
PostgreSQL provides various lock modes to control concurrent
access to data in tables. These modes can be used for application-
controlled locking in situations where MVCC does not give the
desired behavior. Also, most PostgreSQL commands automatically
acquire locks of appropriate modes to ensure that referenced tables
are not dropped or modified in incompatible ways while the
command executes. (For example, TRUNCATE cannot safely be
executed concurrently with other operations on the same table, so it
obtains an exclusive lock on the table to enforce that.) To examine a
list of the currently outstanding locks in a database server, use the
pg_locks system view. For more information on monitoring the
status of the lock manager subsystem, refer to Chapter 27.
Locking
• Table-Level Locks
The list below shows the available lock modes and the contexts in which they
are used automatically by PostgreSQL. You can also acquire any of these
locks explicitly with the command LOCK. Remember that all of these lock
modes are table-level locks, even if the name contains the word “row”; the
names of the lock modes are historical. To some extent the names reflect the
typical usage of each lock mode — but the semantics are all the same. The
only real difference between one lock mode and another is the set of lock
modes with which each conflicts (see Table 13.2). Two transactions cannot
hold locks of conflicting modes on the same table at the same time.
(However, a transaction never conflicts with itself. For example, it might
acquire ACCESS EXCLUSIVE lock and later acquire ACCESS SHARE lock on the
same table.) Non-conflicting lock modes can be held concurrently by many
transactions. Notice in particular that some lock modes are self-conflicting
(for example, an ACCESS EXCLUSIVE lock cannot be held by more than one
transaction at a time) while others are not self-conflicting (for example, an
ACCESS SHARE lock can be held by multiple transactions).
Table-Level Lock Modes

• ACCESS SHARE
• ROW SHARE
• ROW EXCLUSIVE
• SHARE UPDATE EXCLUSIVE
• SHARE
• SHARE ROW EXCLUSIVE
• EXCLUSIVE
Data Concurrency
Time: Transaction 1 UPDATE hr.employee
SET salary=salary+100
WHERE employee_id=100;
Transaction 2 UPDATE hr.employee
SET salary=salary+100
WHERE employee_id=101;
09:00:00 Transaction 3 UPDATE hr.employee
SET salary=salary+100
WHERE employee_id=102;
... ...
Transaction x UPDATE hr.employee
SET salary=salary+100
WHERE employee_id=xxx;
DML Locks
Transaction 1 Transaction 2
SQL> UPDATE employee SQL> UPDATE employee
2 SET salary=salary*1.1 2 SET salary=salary*1.1
3 WHERE employee_id= 107; 3 WHERE employee_id= 106;
1 row updated. 1 row updated.

• Each DML transaction must acquire two locks:


• EXCLUSIVE row lock on the row or rows being updated
• ROW EXCLUSIVE table-level lock on the table
containing the rows
Enqueue Mechanism
• The enqueue mechanism keeps track of:
• Sessions waiting for locks
• Requested lock mode
• Order in which sessions requested the lock

6-mar-21 8:00
Lock Conflicts
Transaction 1 Time Transaction 2
BEGIN TRANSACTION ; BEGIN TRANSACTION;
UPDATE employee SET 9:00:00 UPDATE employee SET
salary=salary+100 WHERE salary=salary+100 WHERE
employee_id=100; employee_id=101;
1 row updated. 1 row updated.
UPDATE employee SET 9:00:05 SELECT sum(salary) FROM
COMMISSION_PCT=0.2 employee;
WHERE employee_id=101; SUM(SALARY)
Session waits enqueued due -----------
to lock conflict. 692634
Session still waiting! Many selects, inserts, updates,
16:30:00 and deletes during the last 7.5
hours, but no commits or
rollbacks!
1 row updated. 16:30:01 commit;
Session continues.
END TRANSACTION; END TRANSACTION;
Possible Causes of Lock Conflicts
• Uncommitted changes
• Long-running transactions
• Unnecessarily high locking levels

OLTP: Online Transaction Processing


Resolving Lock Conflicts with SQL
• SQL statements can be used to determine the blocking session and kill it.

postgres=# SELECT * from pg_locks;


locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid |
mode | granted | fastpath
------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+------+-----------------
+---------+----------
relation | 13318 | 12143 | | | | | | | | 4/14453 | 8528 | AccessShareLock | t |
t
virtualxid | | | | | 4/14453 | | | | | 4/14453 | 8528 | ExclusiveLock | t |t
(2 filas)
SELECT pg_advisory_lock(q.employee_id) FROM
( SELECT employee_id FROM employee WHERE
employee_id=101
LIMIT 100)q;
Deadlocks
Transaction 1 Transaction 2

Begin Transaction Begin Transaction


UPDATE employee UPDATE employee
SET salary = salary x 1.1 9:00 SET manager = 1342
WHERE employee_id = 1000; WHERE employee_id = 2000;
UPDATE employee UPDATE employee
SET salary = salary x 1.1 9:15 SET manager = 1342
WHERE employee_id = 2000; WHERE employee_id = 1000;
ORA-00060:
Deadlock detected while 9:16
waiting for resource
Backup and Recovery
As with everything that contains valuable data, PostgreSQL
databases should be backed up regularly. While the procedure
is essentially simple, it is important to have a clear
understanding of the underlying techniques and assumptions.
There are three fundamentally different approaches to backing
up PostgreSQL data:
• SQL dump
• File system level backup
• Continuous archiving
Each has its own strengths and weaknesses; each is discussed
in turn in the following sections.
Terminology
• Backup strategy may include:
• Entire database (whole)
• Portion of the database (partial)
• Backup type may indicate inclusion of:
• All data blocks within your chosen files (full)
• Only information that has changed since a previous
backup (incremental)
• Cumulative (changes up to last level 0)
• Differential (changes up to last incremental)
• Backup mode may be:
• Offline (consistent, cold)
• Online (inconsistent, hot)
SQL Dump
The idea behind this dump method is to generate a file with SQL commands that,
when fed back to the server, will recreate the database in the same state as it was at
the time of the dump. PostgreSQL provides the utility program pg_dump for this
purpose. The basic usage of this command is:
pg_dump dbname > dumpfile.sql

As you see, pg_dump writes its result to the standard output. We will see below how
this can be useful. While the above command creates a text file, pg_dump can create
files in other formats that allow for parallelism and more fine-grained control of object
restoration. pg_dump is a regular PostgreSQL client application (albeit a particularly
clever one). This means that you can perform this backup procedure from any remote
host that has access to the database. But remember that pg_dump does not operate
with special permissions. In particular, it must have read access to all tables that
you want to back up, so in order to back up the entire database you almost
always have to run it as a database superuser. (If you do not have sufficient
privileges to back up the entire database, you can still back up portions of the
database to which you do have access using options such as -n schema or -t table.)
SQL Dump

An important advantage of pg_dump over the other backup


methods described later is that pg_dump's output can generally
be re-loaded into newer versions of PostgreSQL, whereas file-
level backups and continuous archiving are both extremely
server-version-specific. pg_dump is also the only method that
will work when transferring a database to a different machine
architecture, such as going from a 32-bit to a 64-bit server.
After restoring a backup, it is wise to run ANALYZE on each
database so the query optimizer has useful statistics; see
Section 24.1.3 and Section 24.1.6 for more information. For
more advice on how to load large amounts of data into
PostgreSQL efficiently, refer to Section 14.4.
Pg_dumpall
pg_dump dumps only a single database at a time, and it does
not dump information about roles or tablespaces (because
those are cluster-wide rather than per-database). To support
convenient dumping of the entire contents of a database
cluster, the pg_dumpall program is provided. pg_dumpall
backs up each database in a given cluster, and also
preserves cluster-wide data such as role and tablespace
definitions. The basic usage of this command is:
pg_dumpall > dumpfile.sql
The resulting dump can be restored with psql:
psql -f dumpfile.sql postgres
Restoring the Dump
Text files created by pg_dump and
pg_dumpall are intended to be read in
by the psql program. The general
command form to restore a dump is
psql dbname < dumpfile.sql
Handling Large Databases (linux)
Some operating systems have maximum file size limits that
cause problems when creating large pg_dump output files.
Fortunately, pg_dump can write to the standard output, so you
can use standard Unix tools to work around this potential
problem. There are several possible methods: Use compressed
dumps. You can use your favorite compression program, for
example gzip:
pg_dump dbname | gzip > filename.gz
Reload with:
gunzip -c filename.gz | psql dbname
or:
cat filename.gz | gunzip | psql dbname
Pg_dump
Use split. The split command allows you to split the output
into smaller files that are acceptable in size to the underlying
file system. For example, to make chunks of 1 megabyte:
pg_dump dbname | split -b 1m - filename
Reload with:
cat filename* | psql dbname
Windows:
C:\Program Files\PostgreSQL\12\bin>pg_dump.exe
cd C:\Program Files\PostgreSQL\12\bin
pg_dump.exe -U postgres > db.sql
File System Level Backup
An alternative backup strategy is to directly copy the files
that PostgreSQL uses to store the data in the database;
Section 18.2 explains where these files are located. You can
use whatever method you prefer for doing file system
backups; for example:

tar -cf backup.tar /usr/local/pgsql/data


File System Level Backup
There are two restrictions, however, which make this method impractical, or at least
inferior to the pg_dump method:
1. The database server must be shut down in order to get a usable backup.
Half-way measures such as disallowing all connections will not work (in part
because tar and similar tools do not take an atomic snapshot of the state of the
file system, but also because of internal buffering within the server). Information
about stopping the server can be found in Section 18.5. Needless to say, you also
need to shut down the server before restoring the data.
2. If you have dug into the details of the file system layout of the database, you
might be tempted to try to back up or restore only certain individual tables or
databases from their respective files or directories. This will not work because the
information contained in these files is not usable without the commit log files,
pg_xact/*, which contain the commit status of all transactions. A table file is only
usable with this information. Of course it is also impossible to restore only a table
and the associated pg_xact data because that would render all other tables in the
database cluster useless. So file system backups only work for complete
backup and restoration of an entire database cluster.
File System Level Backup
An alternative file-system backup approach is to make a “consistent
snapshot” of the data directory, if the file system supports that
functionality (and you are willing to trust that it is implemented
correctly). The typical procedure is to make a “frozen snapshot” of
the volume containing the database, then copy the whole data
directory (not just parts, see above) from the snapshot to a backup
device, then release the frozen snapshot. This will work even while
the database server is running. However, a backup created in this
way saves the database files in a state as if the database server
was not properly shut down; therefore, when you start the database
server on the backed-up data, it will think the previous server
instance crashed and will replay the WAL log. This is not a problem;
just be aware of it (and be sure to include the WAL files in your
backup). You can perform a CHECKPOINT before taking the
snapshot to reduce recovery time.
Continuous Archiving and Point-in-
Time Recovery (PITR)
At all times, PostgreSQL maintains a write ahead log (WAL) in the pg_wal/
subdirectory of the cluster's data directory. The log records every change
made to the database's data files. This log exists primarily for crash-safety
purposes: if the system crashes, the database can be restored to consistency
by “replaying” the log entries made since the last checkpoint. However, the
existence of the log makes it possible to use a third strategy for backing up
databases: we can combine a file-system-level backup with backup of the WAL
files. If recovery is needed, we restore the file system backup and then replay
from the backed-up WAL files to bring the system to a current state. This
approach is more complex to administer than either of the previous
approaches, but it has some significant benefits:
• We do not need a perfectly consistent file system backup as the starting
point. Any internal inconsistency in the backup will be corrected by log replay
(this is not significantly different from what happens during crash recovery).
So we do not need a file system snapshot capability, just tar or a similar
archiving tool.
Continuous Archiving and Point-in-
Time Recovery (PITR)
• Since we can combine an indefinitely long sequence of WAL files for
replay, continuous backup can be achieved simply by continuing to
archive the WAL files. This is particularly valuable for large databases,
where it might not be convenient to take a full backup frequently.

• It is not necessary to replay the WAL entries all the way to the end. We
could stop the replay at any point and have a consistent snapshot of
the database as it was at that time. Thus, this technique supports point-
in-time recovery: it is possible to restore the database to its state at any
time since your base backup was taken.
• If we continuously feed the series of WAL files to another machine that
has been loaded with the same base backup file, we have a warm
standby system: at any point we can bring up the second machine and
it will have a nearly-current copy of the database.
Continuous Archiving and Point-in-
Time Recovery (PITR)
NOTE: pg_dump and pg_dumpall do not produce file-system-level backups
and cannot be used as part of a continuous-archiving solution. Such dumps
are logical and do not contain enough information to be used by WAL replay.
As with the plain file-system-backup technique, this method can only
support restoration of an entire database cluster, not a subset. Also, it
requires a lot of archival storage: the base backup might be bulky, and a
busy system will generate many megabytes of WAL traffic that have to be
archived. Still, it is the preferred backup technique in many situations where
high reliability is needed. To recover successfully using continuous archiving
(also called “online backup” by many database vendors), you need a
continuous sequence of archived WAL files that extends back at least as far
as the start time of your backup. So to get started, you should set up and
test your procedure for archiving WAL files before you take your first base
backup. Accordingly, we first discuss the mechanics of archiving WAL files.
Setting Up WAL Archiving
In an abstract sense, a running PostgreSQL system produces
an indefinitely long sequence of WAL records. The system
physically divides this sequence into WAL segment files,
which are normally 16MB apiece (although the segment size
can be altered during initdb). The segment files are given
numeric names that reflect their position in the abstract WAL
sequence. When not using WAL archiving, the system
normally creates just a few segment files and then “recycles”
them by renaming no-longer-needed segment files to higher
segment numbers. It's assumed that segment files whose
contents precede the last checkpoint are no longer of
interest and can be recycled.
Setting Up WAL Archiving
When archiving WAL data, we need to capture the contents of each
segment file once it is filled, and save that data somewhere before the
segment file is recycled for reuse. Depending on the application and
the available hardware, there could be many different ways of “saving
the data somewhere”: we could copy the segment files to an NFS-
mounted directory on another machine, write them onto a tape drive
(ensuring that you have a way of identifying the original name of each
file), or batch them together and burn them onto CDs, or something
else entirely. To provide the database administrator with flexibility,
PostgreSQL tries not to make any assumptions about how the archiving
will be done. Instead, PostgreSQL lets the administrator specify a shell
command to be executed to copy a completed segment file to
wherever it needs to go. The command could be as simple as a cp, or it
could invoke a complex shell script — it's all up to you.
Setting Up WAL Archiving
To enable WAL archiving, set the wal_level configuration
parameter to replica or higher, archive_mode to on, and
specify the shell command to use in the archive_command
configuration parameter. In practice these settings will
always be placed in the postgresql.conf file. In
archive_command, %p is replaced by the path name of the
file to archive, while %f is replaced by only the file name.
(The path name is relative to the current working directory,
i.e., the cluster's data directory.) Use %% if you need to
embed an actual % character in the command. The simplest
useful command is something like:
Setting Up WAL Archiving
archive_command = 'test ! -f
/mnt/server/archivedir/%f && cp %p /
mnt/server/archivedir/%f' # Unix archive_command =
'copy "%p" "C:\\server\\archivedir\\%f"' # Windows

which will copy archivable WAL segments to the directory


/mnt/server/archivedir. (This is an example, not a
recommendation, and might not work on all platforms.) After
the %p and %f parameters have been replaced, the actual
command executed might look like this:
Setting Up WAL Archiving
test ! -f /mnt/server/archivedir/00000001000000A900000065
&& cp pg_wal/00000001000000A900000065 /mnt/server/
archivedir/00000001000000A900000065

A similar command will be generated for each new file to be


archived. The archive command will be executed under the
ownership of the same user that the PostgreSQL server is
running as. Since the series of WAL files being archived
contains effectively everything in your database, you will want
to be sure that the archived data is protected from prying eyes;
for example, archive into a directory that does not have group
or world read access
Setting Up WAL Archiving
It is important that the archive command return zero exit
status if and only if it succeeds. Upon getting a zero result,
PostgreSQL will assume that the file has been successfully
archived, and will remove or recycle it. However, a nonzero
status tells PostgreSQL that the file was not archived; it will
try again periodically until it succeeds. The archive
command should generally be designed to refuse to
overwrite any pre-existing archive file. This is an important
safety feature to preserve the integrity of your archive in
case of administrator error (such as sending the output of
two different servers to the same archive directory).
Setting Up WAL Archiving
It is advisable to test your proposed archive command to ensure that it indeed
does not overwrite an existing file, and that it returns nonzero status in this case.
The example command above for Unix ensures this by including a separate test
step. On some Unix platforms, cp has switches such as -i that can be used to do
the same thing less verbosely, but you should not rely on these without verifying
that the right exit status is returned. (In particular, GNU cp will return status zero
when -i is used and the target file already exists, which is not the desired
behavior.) While designing your archiving setup, consider what will happen if the
archive command fails repeatedly because some aspect requires operator
intervention or the archive runs out of space. For example, this could occur if you
write to tape without an autochanger; when the tape fills, nothing further can be
archived until the tape is swapped. You should ensure that any error condition or
request to a human operator is reported appropriately so that the situation can
be resolved reasonably quickly. The pg_wal/ directory will continue to fill with
WAL segment files until the situation is resolved. (If the file system containing
pg_wal/ fills up, PostgreSQL will do a PANIC shutdown. No committed transactions
will be lost, but the database will remain offline until you free some space.)
Recovering Using a Continuous
Archive Backup
Okay, the worst has happened and you need to recover from your backup. Here is the procedure:
1. Stop the server, if it's running.
2. If you have the space to do so, copy the whole cluster data directory and any tablespaces to a
temporary location in case you need them later. Note that this precaution will require that you have
enough free space on your system to hold two copies of your existing database. If you do not have
enough space, you should at least save the contents of the cluster's pg_wal subdirectory, as it might
contain logs which were not archived before the system went down.
3. Remove all existing files and subdirectories under the cluster data directory and under the root
directories of any tablespaces you are using.
4. Restore the database files from your file system backup. Be sure that they are restored with the right
ownership (the database system user, not root!) and with the right permissions. If you are using
tablespaces, you should verify that the symbolic links in pg_tblspc/ were correctly restored.
5. Remove any files present in pg_wal/; these came from the file system backup and are therefore
probably obsolete rather than current. If you didn't archive pg_wal/ at all, then recreate it with proper
permissions, being careful to ensure that you re-establish it as a symbolic link if you had it set up that
way before.
6. If you have unarchived WAL segment files that you saved in step 2, copy them into pg_wal/. (It is best
to copy them, not move them, so you still have the unmodified files if a problem occurs and you have
to start over.)
Recovering Using a Continuous
Archive Backup
7. Set recovery configuration settings in postgresql.conf (see Section 19.5.4)
and create a file recovery.signal in the cluster data directory. You might
also want to temporarily modify pg_hba.conf to prevent ordinary users
from connecting until you are sure the recovery was successful. 708Backup
and Restore
8. Start the server. The server will go into recovery mode and proceed to read
through the archived WAL files it needs. Should the recovery be terminated
because of an external error, the server can simply be restarted and it will
continue recovery. Upon completion of the recovery process, the server will
remove recovery.signal (to prevent accidentally re-entering recovery mode
later) and then commence normal database operations.
9. Inspect the contents of the database to ensure you have recovered to the
desired state. If not, return to step 1. If all is well, allow your users to
connect by restoring pg_hba.conf to normal.
Recovering Using a Continuous Archive
Backup
The key part of all this is to set up a recovery configuration
that describes how you want to recover and how far the
recovery should run. The one thing that you absolutely must
specify is the restore_command, which tells PostgreSQL how
to retrieve archived WAL file segments. Like the
archive_command, this is a shell command string. It can
contain %f, which is replaced by the name of the desired log
file, and %p, which is replaced by the path name to copy the
log file to. (The path name is relative to the current working
directory, i.e., the cluster's data directory.) Write %% if you
need to embed an actual % character in the command. The
simplest useful command is something like:
Recovering Using a Continuous Archive
Backup
restore_command = 'cp /mnt/server/archivedir/%f %p’

which will copy previously archived WAL segments from the


directory /mnt/server/ archivedir. Of course, you can use something
much more complicated, perhaps even a shell script that requests the
operator to mount an appropriate tape.
It is important that the command return nonzero exit status on failure.
The command will be called requesting files that are not present in the
archive; it must return nonzero when so asked. This is not an error
condition. An exception is that if the command was terminated by a
signal (other than SIGTERM, which is used as part of a database server
shutdown) or an error by the shell (such as command not found), then
recovery will abort and the server will not start up.
High Availability, Load Balancing, and Replication
Feature Matrix

Revisar tabla 26.1 manual postgres 13 Pagina 752


Table 26.1. High Availability, Load Balancing, and Replication
Feature Matrix
DRBD Distributed Replicated Block Device OS: GNU/Linux
Londiste is Skytools' asynchronous primary/secondary replication
system, built atop PGQ.
Slony-I is a "master to multiple slaves" replication system
supporting cascading (e.g. - a node can feed another node which
feeds another node...) and failover.
Bucardo is a replication system for Postgres that supports any
number of sources and targets (aka masters and slaves). It is
asynchronous and trigger based.
pgpool-II is a middleware that works between PostgreSQL servers and a PostgreSQL database
client. It provides the following features.
• Connection Pooling: pgpool-II saves connections to the PostgreSQL servers, and reuse them
whenever a new connection with the same properties (i.e. username, database, protocol
version) comes in. It reduces connection overhead, and improves system's overall throughput.
• Replication: pgpool-II can manage multiple PostgreSQL servers. Using the replication function
enables creating a realtime backup on 2 or more physical disks, so that the service can
continue without stopping servers in case of a disk failure.
• Load Balance: If a database is replicated, executing a SELECT query on any server will return
the same result. pgpool-II takes an advantage of the replication feature to reduce the load on
each PostgreSQL server by distributing SELECT queries among multiple servers, improving
system's overall throughput. At best, performance improves proportionally to the number of
PostgreSQL servers. Load balance works best in a situation where there are a lot of users
executing many queries at the same time.
• Limiting Exceeding Connections: There is a limit on the maximum number of concurrent
connections with PostgreSQL, and connections are rejected after this many connections.
Setting the maximum number of connections, however, increases resource consumption and
affect system performance. pgpool-II also has a limit on the maximum number of connections,
but extra connections will be queued instead of returning an error immediately.
• Parallel Query: Using the parallel query function, data can be divided among the multiple
servers, so that a query can be executed on all the servers concurrently to reduce the overall
execution time. Parallel query works the best when searching large-scale data.
Tablespaces

Tablespaces in PostgreSQL allow database administrators to define locations in the file system where the
files representing database objects can be stored. Once created, a tablespace can be referred to by name
when creating database objects.
By using tablespaces, an administrator can control the disk layout of a PostgreSQL installation. This is
useful in at least two ways. First, if the partition or volume on which the cluster was initialized runs out of
space and cannot be extended, a tablespace can be created on a different partition and used until the
system can be reconfigured.
Second, tablespaces allow an administrator to use knowledge of the usage pattern of database objects to
optimize performance. For example, an index which is very heavily used can be placed on a very fast, highly
available disk, such as an expensive solid state device. At the same time a table storing archived data which
is rarely used or not performance critical could be stored on a less expensive, slower disk system.

To define a tablespace, use the CREATE TABLESPACE command, for example::

CREATE TABLESPACE fastspace LOCATION '/ssd1/postgresql/data';


Tablespaces

The location must be an existing, empty directory that is owned by the PostgreSQL operating system user.
All objects subsequently created within the tablespace will be stored in files underneath this directory. The
location must not be on removable or transient storage, as the cluster might fail to function if the tablespace
is missing or lost.

CREATE TABLE foo(i int) TABLESPACE space1;

SET default_tablespace = space1;


CREATE TABLE foo(i int);

To determine the set of existing tablespaces, examine the pg_tablespace system catalog, for
example
SELECT spcname FROM pg_tablespace;
Indexes
Suppose we have a table similar to this:
CREATE TABLE test1 (
id integer,
content varchar
);
and the application issues many queries of the form:
SELECT content FROM test1 WHERE id = constant;

With no advance preparation, the system would have to scan the entire test1 table, row by row, to find all matching entries. If there
are many rows in test1 and only a few rows (perhaps zero or one) that would be returned by such a query, this is clearly an
inefficient method. But if the system has been instructed to maintain an index on the id column, it can use a more efficient method for
locating matching rows. For instance, it might only have to walk a few levels deep into a search tree.
A similar approach is used in most non-fiction books: terms and concepts that are frequently looked up by readers are collected in
an alphabetic index at the end of the book. The interested reader can scan the index relatively quickly and flip to the appropriate
page(s), rather than having to read the entire book to find the material of interest. Just as it is the task of the author to anticipate the
items that readers are likely to look up, it is the task of the database programmer to foresee which indexes will be useful.

The following command can be used to create an index on the id column, as discussed:
CREATE INDEX test1_id_index ON test1 (id);

The name test1_id_index can be chosen freely, but you should pick something that enables you
to remember later what the index was for.
To remove an index, use the DROP INDEX command. Indexes can be added to and removed from
Indexes

Once an index is created, no further intervention is required: the system will update the index when the table is modified, and it will
use the index in queries when it thinks doing so would be more efficient than a sequential table scan. But you might have to run the
ANALYZE command regularly to update statistics to allow the query planner to make educated decisions. See Chapter 14 for
information about how to find out whether an index is used and when and why the planner might choose not to use an
index.
Indexes can also benefit UPDATE and DELETE commands with search conditions. Indexes can moreover be used in join searches.
Thus, an index defined on a column that is part of a join condition can also significantly speed up queries with joins.
Creating an index on a large table can take a long time. By default, PostgreSQL allows reads (SELECT statements) to occur on the
table in parallel with index creation, but writes (INSERT, UPDATE, DELETE) are blocked until the index build is finished. In
production environments this is often unacceptable. It is possible to allow writes to occur in parallel with index creation, but there are
several caveats to be aware of — for more information see Building Indexes Concurrently.
After an index is created, the system has to keep it synchronized with the table. This adds overhead to data manipulation operations.
Therefore indexes that are seldom or never used in queries should be removed.
Index Types
PostgreSQL provides several index types: B-tree, Hash, GiST, SP-GiST, GIN and BRIN. Each index type uses
a different algorithm that is best suited to different types of queries. By default, the CREATE INDEX command
creates B-tree indexes, which fit the most common situations.
B-trees can handle equality and range queries on data that can be sorted into some ordering. In particular, the
PostgreSQL query planner will consider using a B-tree index whenever an indexed column is involved in a
comparison using one of these operators:
<
<=
=
>=
>
Constructs equivalent to combinations of these operators, such as BETWEEN and IN, can also be
implemented with a B-tree index search. Also, an IS NULL or IS NOT NULL condition on an index column can
be used with a B-tree index.
The optimizer can also use a B-tree index for queries involving the pattern matching operators LIKE and ~ if
the pattern is a constant and is anchored to the beginning of the string — for example, col LIKE 'foo%' or col ~
'^foo', but not col LIKE '%bar'. However, if your database does not use the C locale you will need to create the
index with a special operator class to support indexing of pattern-matching queries; see Section 11.10 below. It
is also possible to use B-tree indexes for ILIKE and ~*, but only if the pattern starts with non-alphabetic
characters, i.e., characters that are not affected by upper/lower case conversion.
B-tree indexes can also be used to retrieve data in sorted order. This is not always faster than a simple scan
Index Types
Hash indexes can only handle simple equality comparisons. The query planner will consider using a hash
index whenever an indexed column is involved in a comparison using the = operator. The following command
is used to create a hash index:
CREATE INDEX name ON table USING HASH (column);

GiST indexes are not a single kind of index, but rather an infrastructure within which many different indexing
strategies can be implemented. Accordingly, the particular operators with which a GiST index can be used vary
depending on the indexing strategy (the operator class). As an example, the standard distribution of
PostgreSQL includes GiST operator classes for several two-dimensional geometric data types, which support
indexed queries using these operators:
<
&<
&>
>>
<<|
&<|
|&>
|>>
@>
<@
~=
&&
Index Types

See Section 9.11 for the meaning of these operators.) The GiST operator classes included in the standard
distribution are documented in Table 64.1. Many other GiST operator classes are available in the contrib
collection or as separate projects. For more information see Chapter 64.
GiST indexes are also capable of optimizing “nearest-neighbor” searches, such as

SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;

which finds the ten places closest to a given target point. The ability to do this is again dependent on the
particular operator class being used. In Table 64.1, operators that can be used in this way are listed in the
column “Ordering Operators”.

SP-GiST indexes, like GiST indexes, offer an infrastructure that supports various kinds of searches.
SP-GiST permits implementation of a wide range of different non-balanced disk-based data structures, such
as quadtrees, k-d trees, and radix trees (tries). As an example, the standard distribution of PostgreSQL
includes SP-GiST operator classes for two-dimensional points.
Performance Tips
Query performance can be affected by many things. Some of these can be controlled by the user, while others
are fundamental to the underlying design of the system. This chapter provides some hints about
understanding and tuning PostgreSQL performance.

Using EXPLAIN

PostgreSQL devises a query plan for each query it receives. Choosing the right plan to match the query
structure and the properties of the data is absolutely critical for good performance, so the system includes a
complex planner that tries to choose good plans. You can use the EXPLAIN command to see what query plan
the planner creates for any query. Plan-reading is an art that requires some experience to master, but this
section attempts to cover the basics.
Examples in this section are drawn from the regression test database after doing a VACUUM ANALYZE, using
9.3 development sources. You should be able to get similar results if you try the examples yourself, but your
estimated costs and row counts might vary slightly because ANALYZE's statistics are random samples rather
than exact, and because costs are inherently somewhat platform-dependent.
The examples use EXPLAIN's default “text” output format, which is compact and convenient for humans to
read. If you want to feed EXPLAIN's output to a program for further analysis, you should use one of its
machine-readable output formats (XML, JSON, or YAML) instead.
Performance Tips
EXPLAIN Basics
The structure of a query plan is a tree of plan nodes. Nodes at the bottom level of the tree are scan nodes:
they return raw rows from a table. There are different types of scan nodes for different table access methods:
sequential scans, index scans, and bitmap index scans. There are also non-table row sources, such as
VALUES clauses and set-returning functions in FROM, which have their own scan node types. If the query
requires joining, aggregation, sorting, or other operations on the raw rows, then there will be additional nodes
above the scan nodes to perform these operations. Again, there is usually more than one possible way to do
these operations, so different node types can appear here too.
The output of EXPLAIN has one line for each node in the plan tree, showing the basic node type plus the cost
estimates that the planner made for the execution of that plan node. Additional lines might appear, indented
from the node's summary line, to show additional properties of the node. The very first line (the summary line
for the topmost node) has the estimated total execution cost for the plan; it is this number that the planner
seeks to minimize.

Here is a trivial example, just to show what the output looks like:

EXPLAIN SELECT * FROM te;

QUERY PLAN
-------------------------------------------------------------
Seq Scan on tenk1 (cost=0.00..458.00 rows=10000 width=244)
Performance Tips
Since this query has no WHERE clause, it must scan all the rows of the table, so the planner has chosen to
use a simple sequential scan plan. The numbers that are quoted in parentheses are (left to right):

• Estimated start-up cost. This is the time expended before the output phase can begin, e.g., time to do the
sorting in a sort node.

• Estimated total cost. This is stated on the assumption that the plan node is run to completion, i.e., all
available rows are retrieved. In practice a node's parent node might stop short of reading all available rows
(see the LIMIT example below).
Estimated number of rows output by this plan node. Again, the node is assumed to be run to completion.
• Estimated average width of rows output by this plan node (in bytes).
The costs are measured in arbitrary units determined by the planner's cost parameters (see Section 19.7.2).
Traditional practice is to measure the costs in units of disk page fetches; that is, seq_page_cost is
conventionally set to 1.0 and the other cost parameters are set relative to that. The examples in this section
are run with the default cost parameters.
It's important to understand that the cost of an upper-level node includes the cost of all its child nodes.
It's also important to realize that the cost only reflects things that the planner cares about. In particular, the
cost does not consider the time spent transmitting result rows to the client, which could be an important factor
in the real elapsed time; but the planner ignores it because it cannot change it by altering the plan. (Every
correct plan will output the same row set, we trust.)
Performance Tips

The rows value is a little tricky because it is not the number of rows processed or scanned by the plan node,
but rather the number emitted by the node. This is often less than the number scanned, as a result of filtering
by any WHERE-clause conditions that are being applied at the node. Ideally the top-level rows estimate will
approximate the number of rows actually returned, updated, or deleted by the query.

Returning to our example:


EXPLAIN SELECT * FROM tenk1;
QUERY PLAN
-------------------------------------------------------------
Seq Scan on tenk1 (cost=0.00..458.00 rows=10000 width=244)

These numbers are derived very straightforwardly. If you do:


SELECT relpages, reltuples FROM pg_class WHERE relname = 'tenk1';

you will find that tenk1 has 358 disk pages and 10000 rows. The estimated cost is computed as (disk pages
read * seq_page_cost) + (rows scanned * cpu_tuple_cost). By default, seq_page_cost is 1.0 and
cpu_tuple_cost is 0.01, so the estimated cost is (358 * 1.0) + (10000 * 0.01) = 458.
Performance Tips
Now let's modify the query to add a WHERE condition:

EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 7000;

QUERY PLAN
------------------------------------------------------------
Seq Scan on tenk1 (cost=0.00..483.00 rows=7001 width=244)

Filter: (unique1 < 7000)

Notice that the EXPLAIN output shows the WHERE clause being applied as a “filter” condition attached to the
Seq Scan plan node. This means that the plan node checks the condition for each row it scans, and outputs
only the ones that pass the condition. The estimate of output rows has been reduced because of the WHERE
clause. However, the scan will still have to visit all 10000 rows, so the cost hasn't decreased; in fact it has
gone up a bit (by 10000 * cpu_operator_cost, to be exact) to reflect the extra CPU time spent checking the
WHERE condition.
The actual number of rows this query would select is 7000, but the rows estimate is only approximate.
If you try to duplicate this experiment, you will probably get a slightly different estimate; moreover, it can
change after each ANALYZE command, because the statistics produced by ANALYZE are taken from a
randomized sample of the table.
Now, let's make the condition more restrictive:
Performance Tips

EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100;


QUERY PLAN
-------------------------------------------------------------------
-----------
Bitmap Heap Scan on tenk1 (cost=5.07..229.20 rows=101 width=244)
Recheck Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04
rows=101 width=0)
Index Cond: (unique1 < 100)

Here the planner has decided to use a two-step plan: the child plan node visits an index to find the locations of
rows matching the index condition, and then the upper plan node actually fetches those rows from the table
itself. Fetching rows separately is much more expensive than reading them sequentially, but because not all
the pages of the table have to be visited, this is still cheaper than a sequential scan. (The reason for using two
plan levels is that the upper plan node sorts the row locations identified by the index into physical order before
reading them, to minimize the cost of separate fetches. The “bitmap” mentioned in the node names is the
mechanism that does the sorting.)
Performance Tips

Now let's add another condition to the WHERE clause:

EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND stringu1 = 'xxx';
QUERY PLAN
------------------------------------------------------------------------------
Bitmap Heap Scan on tenk1 (cost=5.04..229.43 rows=1 width=244)
Recheck Cond: (unique1 < 100)
Filter: (stringu1 = 'xxx'::name)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04
rows=101 width=0)
Index Cond: (unique1 < 100)

The added condition stringu1 = 'xxx' reduces the output row count estimate, but not the cost because we still
have to visit the same set of rows. Notice that the stringu1 clause cannot be applied as an index condition,
since this index is only on the unique1 column. Instead it is applied as a filter on the rows retrieved by the
index. Thus the cost has actually gone up slightly to reflect this extra checking.
Performance Tips
EXPLAIN ANALYZE
It is possible to check the accuracy of the planner's estimates by using EXPLAIN's ANALYZE option.
With this option, EXPLAIN actually executes the query, and then displays the true row counts and true run time
accumulated within each plan node, along with the same estimates that a plain EXPLAIN shows. For example,
we might get a result like this:
EXPLAIN ANALYZE SELECT *
FROM tenk1 t1, tenk2 t2
WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=4.65..118.62 rows=10 width=488) (actual
time=0.128..0.377 rows=10 loops=1)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.47 rows=10
width=244) (actual time=0.057..0.121 rows=10 loops=1)
Recheck Cond: (unique1 < 10)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36
rows=10 width=0) (actual time=0.024..0.024 rows=10 loops=1)
Index Cond: (unique1 < 10)
-> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.91
rows=1 width=244) (actual time=0.021..0.022 rows=1 loops=10)
Index Cond: (unique2 = t1.unique2)
Planning time: 0.181 ms
Performance Tips

Note that the “actual time” values are in milliseconds of real time, whereas the cost estimates are expressed in
arbitrary units; so they are unlikely to match up. The thing that's usually most important to look for is whether
the estimated row counts are reasonably close to reality. In this example the estimates were all dead-on, but
that's quite unusual in practice.
In some query plans, it is possible for a subplan node to be executed more than once. For example, the inner
index scan will be executed once per outer row in the above nested-loop plan. In such cases, the loops value
reports the total number of executions of the node, and the actual time and rows values shown are averages
per-execution. This is done to make the numbers comparable with the way that the cost estimates are shown.
Multiply by the loops value to get the total time actually spent in the node.
In the above example, we spent a total of 0.220 milliseconds executing the index scans on tenk2.
Performance Tips
Statistics Used by the Planner
Single-Column Statistics

As we saw in the previous section, the query planner needs to estimate the number of rows retrieved by a
query in order to make good choices of query plans. This section provides a quick look at the statistics that the
system uses for these estimates.
One component of the statistics is the total number of entries in each table and index, as well as the number of
disk blocks occupied by each table and index. This information is kept in the table pg_class, in the columns
reltuples and relpages. We can look at it with queries similar to this one:

SELECT relname, relkind, reltuples, relpages


FROM pg_class
WHERE relname LIKE 'tenk1%';

Here we can see that tenk1 contains 10000 rows, as do its indexes, but the indexes are (unsurprisingly) much
smaller than the table.
For efficiency reasons, reltuples and relpages are not updated on-the-fly, and so they usually contain somewhat
out-of-date values. They are updated by VACUUM, ANALYZE, and a few DDL commands such as CREATE
INDEX. A VACUUM or ANALYZE operation that does not scan the entire table (which is commonly the case)
will incrementally update the reltuples count on the basis of the part of the table it did scan, resulting in an
approximate value. In any case, the planner will scale the values it finds in pg_class to match the current
physical table size, thus obtaining a closer approximation.
Performance Tips
Most queries retrieve only a fraction of the rows in a table, due to WHERE clauses that restrict the rows to be
examined. The planner thus needs to make an estimate of the selectivity of WHERE clauses, that is, the
fraction of rows that match each condition in the WHERE clause. The information used for this task is stored in
the pg_statistic system catalog. Entries in pg_statistic are updated by the ANALYZE and VACUUM ANALYZE
commands, and are always approximate even when freshly updated.
Rather than look at pg_statistic directly, it's better to look at its view pg_stats when examining the statistics
manually. pg_stats is designed to be more easily readable. Furthermore, pg_stats is readable by all, whereas
pg_statistic is only readable by a superuser. (This prevents unprivileged users from learning something about
the contents of other people's tables from the statistics. The pg_stats view is restricted to show only rows about
tables that the current user can read.) For example, we might do:

SELECT attname, inherited, n_distinct,


array_to_string(most_common_vals, E'\n') as most_common_vals
FROM pg_stats
WHERE tablename = 'road';
Performance Tips
Note that two rows are displayed for the same column, one corresponding to the complete inheritance hierarchy
starting at the road table (inherited=t), and another one including only the road table itself (inherited=f).
The amount of information stored in pg_statistic by ANALYZE, in particular the maximum number of entries in
the most_common_vals and histogram_bounds arrays for each column, can be set on a column-by-column
basis using the ALTER TABLE SET STATISTICS command, or globally by setting the default_statistics_target
configuration variable. The default limit is presently 100 entries. Raising the limit might allow more accurate
planner estimates to be made, particularly for columns with irregular data distributions, at the price of
consuming more space in pg_statistic and slightly more time to compute the estimates. Conversely, a lower
limit might be sufficient for columns with simple data distributions.

Extended Statistics

It is common to see slow queries running bad execution plans because multiple columns used in the query
clauses are correlated. The planner normally assumes that multiple conditions are independent of each other,
an assumption that does not hold when column values are correlated. Regular statistics, because of their per-
individual-column nature, cannot capture any knowledge about cross-column correlation. However, PostgreSQL
has the ability to compute multivariate statistics, which can capture such information. Because the number of
possible column combinations is very large, it's impractical to compute multivariate statistics automatically.
Instead, extended statistics objects, more often called just statistics objects, can be created to instruct the
server to obtain statistics across interesting sets of columns.
Performance Tips
Statistics objects are created using the CREATE STATISTICS command. Creation of such an object merely
creates a catalog entry expressing interest in the statistics. Actual data collection is performed by ANALYZE
(either a manual command, or background auto-analyze). The collected values can be examined in the
pg_statistic_ext_data catalog.
ANALYZE computes extended statistics based on the same sample of table rows that it takes for computing
regular single-column statistics. Since the sample size is increased by increasing the statistics target for the
table or any of its columns (as described in the previous section), a larger statistics target will normally result in
more accurate extended statistics, as well as more time spent calculating them.
The following subsections describe the kinds of extended statistics that are currently supported.

Revisar pagina 491 manual postgres 13.2

You might also like