Postgresql 95231693412781986
Postgresql 95231693412781986
hakibenita.com
About Me
Started as an Oracle DBA
Worked on DWH and DSS systems
Lead a team developers and DBAs
Got into web development, mainly Python and Django
Leading the development of a large ticketing platform
POLL
What is your job title?
DBA
Developer
Sysadmin / SRE
Analyst / Data ops / Data scientist
Student
Management
Other
POLL
What is your main use of data / SQL?
Ad-Hoc Reports (sales reports, operational reports, etc.)
Research / Analysis (BI / DWH / Dashboards/ Data exploration
etc.)
Development (Backend Development / ETL / Data pipelines
etc.)
POLL
How would you rate your level of proficiency with
databases?
Novice
Intermediate
Advanced
The DBA Spectrum
Infrastructure
Operating system, storage, network, installation...
Infra DBA, SRE, Sysadmin
Infrastructure
on
k
e
OS
or
ag
ti
or
tw
la
St
Ne
al
st
In
The DBA Spectrum
Application
SQL, ORMs, BI, dashboards, reporting...
Developers, data scientists, analysts
Infrastructure Application
on
k
e
OS
d
M
BI
or
ag
SQ
in
or
OR
ti
or
tw
rt
ba
la
St
Ne
po
sh
al
Re
Da
st
In
The DBA Spectrum
Data
Data model, tables, indexes, users, performance tunning
Application DBAs, developers, data ops
Infrastructure Data Application
l
e
s
s
es
on
k
e
OS
d
de
M
BI
nc
xe
er
or
ag
SQ
in
or
OR
ti
bl
mo
de
ma
Us
or
tw
rt
ba
la
Ta
In
or
St
Ne
po
sh
ta
al
rf
Re
Da
Da
st
Pe
In
What you’ll gain from this training
Get comfortable with PostgreSQL
Perform basic administrative tasks
Create and manage users and permissions
Create and manage tables
Evaluate query performance
Create indexes to speed up query execution
Just the tip of the iceberg...
“ Give a man a fish and you feed him for a day
Teach a man to fish and you feed him for a lifetime “
In the process you will also
Get comfortable with PostgreSQL CLI and documentation
Figure out how to find answers on your own
Evaluate different aspects of database performance
History
SQL
Structured Query Language
Used for interacting with relational databases (RDBMS)
Invented in the early 70s at IBM based on work by Edgar F.
Codd
Became a standard in 1986 (ANSI-86)
Standard revised in 1992 (ANSI-92)
PostgreSQL
Based on the Berkeley
POSTGRES project from
1986
Originally named
Postgres95
Free Open Source
Growing fast!
Tools
PostgreSQL Documentation
Excellent resource
Suited for both experts and beginners
Use it! Bookmark it!
https://www.postgresql.org/docs/current/
psql
PostgreSQL interactive terminal
Comes with PostgreSQL installation
$ psql
psql (13.2)
Type "help" for help.
postgres=#
https://www.postgresql.org/docs/13/app-psql.html
Don't memorize anything!
List all commands
postgres=# \?
General
\copyright show PostgreSQL usage and distribution terms
\crosstabview [COLUMNS] execute query and display results in crosstab
\errverbose show most recent error message at maximum verbosity
\g [(OPTIONS)] [FILE] e
....
Don't memorize anything!
Get command syntax
postgres=# \h DELETE
Command: DELETE
Description: delete rows of a table
Syntax:
[ WITH [ RECURSIVE ] with_query [, ...] ]
DELETE FROM [ ONLY ] table_name [ * ] [ [ AS ] alias ]
[ USING from_item [, ...] ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
URL: https://www.postgresql.org/docs/13/sql-delete.html
Don't memorize anything!
Use auto complete
postgres=# \set E<tab>
ECHO ECHO_HIDDEN ENCODING
db1 postgres
Database
Has a designated storage area on the file system
Contains database objects and definitions such as tables,
indexes and sequences
Owned by a user
db1
User
Granted object and system permissions
Used to authenticate a client application
PostgreSQL Server 1
db1 db2
Client Server
Client application establish connection with database server
Database server allocate a server process for the session
Can have many concurrent active connections (
show max_connections )
PostgreSQL Server 1
Server Shared
Process Memmory db1
Memory
Shared memory: Shared by all server processes
Local memory: Used by a single server process
PostgreSQL Server 1
Server Processes
Shared
Memory db1
Memory: Shared Buffers
Shared by all server processes
Keep frequently accessed objects in memory for fast retrieval
Default 128MB
show shared_buffers
PostgreSQL Server 1
Server Processes
Shared
Memory db1
Memory: Local Memory
Allocated for each backend process
work_mem : sorts and hash tables (default 1MB)
temp_buffers : storing temporary tables (default 8MB)
maintenance_work_mem : vacuum and create index operations
(default 64MB) PostgreSQL Server 1
Server Processes
Shared
Memory db1
Write Ahead Log (WAL)
A log of all changes to tables and indexes
Used to restore the database in case of disaster
Can be used to maintain replication
Enables point in time recovery
Recap
Architecture and Terminology
Cluster -> database
Memory structures
Shared memory
Local memory
WAL
Database
Database
Contains database objects and definitions such as tables,
indexes and sequences
Owned by a user
db1
Database
Creating a database
postgres=# CREATE DATABASE db1 OWNER postgres;
CREATE DATABASE
-O : database owner
Database
List databases
postgres=# \l
List of databases
Name │ Owner │ Encoding
────────────────┼───────────────┼──────────
db1 │ postgres │ UTF8
postgres │ postgres │ UTF8
template0 │ postgres │ UTF8
template1 │ postgres │ UTF8
Table
Data in relational database is stored in tables
Tables have columns
Can define constraints
Use indexes to speed access to data stored in tables
Table
Creating a table
db1=# CREATE TABLE users (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
active BOOLEAN,
name TEXT
);
CREATE TABLE
Table
Dropping a table
db1=# DROP TABLE users;
DROP TABLE
Table
Drop a table only if it exists
db1=# DROP TABLE IF EXISTS users;
Get the same outcome every time you execute the script
Table
Inspecting a table
db1=# \d users
Table "public.users"
Column │ Type │ Nullable │ Default
────────┼─────────┼──────────┼──────────────────────────────
id │ integer │ not null │ generated always as identity
active │ boolean │ │
name │ text │ │
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
Table
Listing all tables
db1=# \dt
List of relations
Schema │ Name │ Type │ Owner
────────┼───────┼───────┼─────────
public │ users │ table │ postgres
Table
Searching for tables
db1=# \dt foo*
Did not find any relation named "foo*"
db1=# \dt u*
List of relations
Schema │ Name │ Type │ Owner
────────┼───────┼───────┼─────────
public │ users │ table │ postgres
Table
Alter an existing table
db1=# ALTER TABLE users ALTER COLUMN active SET DEFAULT true;
ALTER TABLE
db1=# \d users
Table "public.users"
Column │ Type │ Nullable │ Default
────────┼─────────┼──────────┼──────────────────────────────
id │ integer │ not null │ generated always as identity
active │ boolean │ │ true
name │ text │ │
Table
Default value is used when not explicitly provided
db1=# INSERT INTO users (name) VALUES ('Haki Benita');
INSERT 0 1
CREATE VIEW
View
Querying a view
db1=# INSERT INTO users (name, active) VALUES ('Bob Bar', false);
INSERT 0 1
View definition:
SELECT users.id, users.name
FROM users
WHERE users.active;
Temporary Views
Dropped automatically at the end of the session
db1=# CREATE TEMPORARY VIEW inactive_users AS
SELECT *
FROM users
WHERE NOT active;
CREATE VIEW
public pg_catalog
Schema
Creating a schema
db1=# CREATE SCHEMA restricted;
CREATE SCHEMA
db1=# \dn
List of schemas
Name │ Owner
────────────┼──────────
restricted │ postgres
public │ postgres
Schema
Creating tables in a schema
db1=# CREATE TABLE restricted.credentials (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id INT,
password TEXT NOT NULL
);
CREATE TABLE
📖 "Synonyms" in PostgreSQL
Information Schema
A special schema in every database "pg_catalog"
Contains information about database objects
db1
public pg_catalog
Information Schema
Information about tables
db1=# SELECT * FROM pg_tables WHERE tablename = 'users';
─[ RECORD 1 ]─────────
schemaname │ public
tablename │ users
tableowner │ postgres
tablespace │ ¤
hasindexes │ t
hasrules │ f
hastriggers │ t
rowsecurity │ f
Information Schema
Information about indexes
db1=# SELECT * FROM pg_indexes WHERE tablename = 'users';
─[ RECORD 1 ]───────────────────────────────────────────────────────────────
schemaname │ public
tablename │ users
indexname │ users_pkey
tablespace │ ¤
indexdef │ CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id)
Information Schema
Information about all database objects:
db1=# SELECT relname, relkind FROM pg_class WHERE relname LIKE '%users%';
relname │ relkind
──────────────┼─────────
users │ r
users_pkey │ i
users_id_seq │ S
active_users │ v
But you want to produce the report to a file, like \copy does...
A Problem: COPY Trick
psql has an option to send query output to file
db1=# \?
...
\g [(OPTIONS)] [FILE]
execute query (and send results to file or |pipe);
...
A Problem: COPY Trick
Use \g to write COPY output to a local file!
db1=# COPY (SELECT u.id, u.name, count(*) AS credentials
FROM users u LEFT JOIN restricted.credentials c ON u.id = c.user_id
WHERE u.active
GROUP BY 1, 2
ORDER BY 3 DESC)
TO STDOUT WITH CSV HEADER \g report.csv
COPY 4
db1=# \d users
Table "public.users"
Column │ Type │ Nullable │ Default
────────┼───────────────────────┼──────────┼──────────────────────────────
id │ integer │ not null │ generated always as identity
active │ boolean │ not null │ true
name │ character varying(20) │ │
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
Not Null Constraint
Field is now required
db1=# INSERT INTO users (name, active) VALUES ('foo', NULL);
ERROR: null value in column "active" of relation "users" violates not-null constraint
DETAIL: Failing row contains (3, null, foo).
Creates a sequence
Automatically populate PK with next values
Used to be serial (soft-deprecated starting PostgreSQL 10)
Unique Constraint
Ensure one or more fields are unique
Unique Constraint
Name must be unique
db1=# ALTER TABLE users ADD CONSTRAINT users_name_unique UNIQUE(name);
ALTER TABLE
Unique Constraint
db1=# \d users
Table "public.users"
Column │ Type │ Collation │ Nullable │ Default
────────┼───────────────────────┼───────────┼──────────┼──────────────────────────────
id │ integer │ │ not null │ generated always as identity
active │ boolean │ │ not null │ true
name │ character varying(20) │ │ │
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"users_name_unique" UNIQUE CONSTRAINT, btree (name)
db1=# \d users
Column │ Type
──────────┼──────────────────────
id │ integer
active │ boolean
name │ character varying(20)
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
Foreign Key
Add a foreign key between users and their credentials
db1=# ALTER TABLE restricted.credentials ADD CONSTRAINT user_fk
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE;
ALTER TABLE
Foreign Key
db1=# \d restricted.credentials
Table "restricted.credentials"
Column │ Type │ Nullable │ Default
──────────┼─────────┼──────────┼──────────────────────────────
id │ integer │ not null │ generated always as identity
user_id │ integer │ │
password │ text │ not null │
Indexes:
"credentials_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"user_fk" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
Foreign Key
db1=# ALTER TABLE restricted.credentials ADD CONSTRAINT user_fk
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE;
ALTER TABLE
ALTER TABLE
db1=# INSERT INTO restricted.credentials (user_id, password) VALUES (8, 'secret') RETURNING *;
id │ user_id │ password
────┼─────────┼──────────
2 │ 8 │ secret
INSERT 0 1
Foreign Key
Delete user
db1=# DELETE FROM users WHERE id = 8;
DELETE 1
+1
redirect
https://sho.rt/jdj23d https://www.oreilly.com
Exercise
Getting Started with PostgreSQL: Creating and managing tables
Launch Katacoda scenario »
Users and Privileges
User
Creating a user
db1=# CREATE USER app PASSWORD 'secret';
CREATE ROLE
db1=>
-d name of database
-U name of user
-W prompt for password
Privileges
Types of privileges
SELECT / UPDATE / DELETE / TRUNCATE on TABLE
CONNECT on DATABASE
CREATE on DATABASE
more...
Privileges
Enforce privileges
db1=> \conninfo
You are connected to database "db1" as user "app".
Notice the user still has update, insert and select privileges
Privileges
Revoke privileges
db1=# \connect db1 app
You are now connected to database "db1" as user "app".
grantee │ privilege_type
─────────┼────────────────
app │ INSERT
app │ SELECT
app │ UPDATE
Privileges
Grant privileges on schema
db1=> \connect db1 postgres
You are now connected to database "db1" as user "postgres".
12 320
73 120
Query Optimizer
3. Choose the plan with the lowest cost
The lower the cost, the faster the execution is (expected) to
be
55 42
100
12 320
73 120
Execution Plan: The EXPLAIN Command
EXPLAIN SELECT * FROM sale;
QUERY PLAN
-----------------------------------------------------------
Seq Scan on sale
(cost=0.00..1751.00 rows=100000 width=33)
Use the index to find the sales with ID less than 100
Execution Plan
Using the EXPLAIN command
EXPLAIN SELECT * FROM sale WHERE id < 100000;
QUERY PLAN
-----------------------------------------------------------
Seq Scan on sale (cost=0.00..2001.00 rows=99999 width=33)
Filter: (id < 100000)
Scan the entire table and to find sales with ID less than 100000
Execution Plan
EXPLAIN (ANALYZE ON, TIMING ON)
SELECT * FROM sale;
QUERY PLAN
-------------------------------------------------------------------------------------
Seq Scan on sale (cost=0.00..1751 rows=100000 width=33)
(actual time=0.026..11.209 rows=100000 loops=1)
Planning Time: 0.105 ms
Execution Time: 15.568 ms
1 2 3 4 5 6 7 8 9
leaf leaf leaf
B-Tree Index
Search for the value 5 :
1. Scan the index root
2. Find the leaf block
3. Search the value in the leaf
3 7
1 2 3 4 5 6 7 8 9
B-Tree Index
Create a B-Tree index
db1=# CREATE INDEX shorturl_hits_ix ON shorturl USING btree(hits);
CREATE INDEX
Index key and include the value of url in the index leaf
Inclusive Index
Fulfill queries using just the index:
db1=# EXPLAIN (ANALYZE, TIMING) SELECT url FROM shorturl WHERE key = 'key123';
QUERY PLAN
-------------------------------------------------------------------
Index Only Scan using shorturl_key_including_url_ix on shorturl
Index Cond: (key = 'key123'::text)
Heap Fetches: 0
Planning Time: 0.534 ms
Execution Time: 0.120 ms
-- With index
db1=# SELECT * FROM shorturl WHERE substring(url FROM '.*://([^/]+)') = 'hakibenita.com';
Execution Time: 0.914
Much faster!
Function Based Index
Index will only be considered only if the expressions is
exactly the same
Useful for existing applications (you can't change)
Consider calculated columns as an alternative
Recap
B-Tree is the default index type and what you normally need
Used to enforce unique constraints
Many features:
Partial
Function based
Inclusive
more...
Performance
What's it all about
Performance
CPU
Memory
Disk Space
Cost
Not just speed!
Table Size
Functions to get table size
Function Description
pg_relation_size Table size
pg_table_size Including TOAST
pg_total_relation_size Including TOAST & Indexes
QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on shorturl (cost=0.00..2239.00 rows=1 width=48)
Filter: (url = 'https://hakibenita.com/postgresql-hash-index'::text)
Rows Removed by Filter: 99998
Planning Time: 0.139 ms
Execution Time: 15.506 ms
QUERY PLAN
---------------------------------------------------------------------------------
Index Scan using shorturl_url_ix on shorturl (cost=0.42..8.44 rows=1 width=48)
Index Cond: (url = 'https://hakibenita.com/postgresql-hash-index'::text)
Planning Time: 0.334 ms
Execution Time: 0.109 ms
QUERY PLAN
--------------------------------------------------------------------------------
Index Scan using shorturl_url_hix on shorturl (cost=0.00..8.02 rows=1 width=48)
Index Cond: (url = 'https://hakibenita.com/postgresql-hash-index'::text)
Planning Time: 0.242 ms
Execution Time: 0.061 ms
3. For each range, keep only the minimum and maximum values:
[1-3] [4-6] [7-9]
BRIN Index
Use the index to search for the value 5:
[1–3] 💀 Definitely not here
[4–6] 💩 Might be here
[7–9] 💀 Definitely not here
attname | correlation
------------+--------------
id | 1
key | 0.0018741399
url | 0.0033386275
hits | 0.0015433382
created_at | 1