Professional Documents
Culture Documents
BRUCE MOMJIAN
1 / 110
No One Likes Locking But it Is Necessary
for Proper Database Operation
https://www.flickr.com/photos/mplemmon/
2 / 110
Outline
1. Locking Introduction
2. Transaction Identifiers
3. Lock Types
4. Lock Examples
3 / 110
Introduction
https://www.flickr.com/photos/54409200@N04/
4 / 110
What an Adventure! Xyzzy
http://en.wikipedia.org/wiki/Colossal_Cave_Adventure#Maze_of_twisty_little_passages
5 / 110
The Real Postgres Lock Types
ACCESS SHARE
ROW SHARE
ROW EXCLUSIVE
SHARE UPDATE EXCLUSIVE
SHARE
SHARE ROW EXCLUSIVE
EXCLUSIVE
ACCESS EXCLUSIVE
6 / 110
Share/Exclusive Types
ACCESS SHARE
ROW SHARE
ROW EXCLUSIVE
SHARE UPDATE EXCLUSIVE
SHARE
SHARE ROW EXCLUSIVE
EXCLUSIVE
ACCESS EXCLUSIVE
7 / 110
Row/Access Types
ACCESS SHARE
ROW SHARE
ROW EXCLUSIVE
SHARE UPDATE EXCLUSIVE
SHARE
SHARE ROW EXCLUSIVE
EXCLUSIVE
ACCESS EXCLUSIVE
8 / 110
MVCC
9 / 110
Transaction Identifiers
https://www.flickr.com/photos/grendelkhan/
10 / 110
Keep Your Eye on the Red (Text)
https://www.flickr.com/photos/alltheaces/
11 / 110
What Is Our Process Identifier (PID)?
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
All queries used in this presentation are available at http://momjian.
us/main/writings/pgsql/locking.sql.
12 / 110
What Is Our Virtual XID (VXID)
13 / 110
What Is Our Backend Id?
SELECT *
FROM pg_stat_get_backend_idset() AS t(id)
WHERE pg_stat_get_backend_pid(id) = pg_backend_pid();
id
----
2
(1 row)
The maximum backend id is set by max_connections.
14 / 110
The VXID Increments
15 / 110
Getting a Real/External/Non-Virtual XID
BEGIN WORK;
BEGIN
ANALYZE pg_language;
ANALYZE
16 / 110
Getting a Real/External/Non-Virtual XID
SELECT virtualtransaction AS vxid, transactionid::text
FROM pg_locks
WHERE pid = pg_backend_pid()
ORDER BY 1, 2
LIMIT 1;
vxid | transactionid
------+---------------
2/12 | 674
(1 row)
SELECT txid_current();
txid_current
--------------
674
(1 row)
COMMIT;
COMMIT
Transaction identifiers range from 3 to 4 billion (2^32). Zero(0) is an
invalid transaction id, and 1 and 2 are used for setting frozen xids
(committed and aborted).
17 / 110
Requesting Your XID Assigns One
BEGIN WORK;
BEGIN
18 / 110
Requesting Your XID Assigns One
COMMIT;
COMMIT
19 / 110
Lock Types
https://www.flickr.com/photos/proimos/ http://www.flickr.com/photos/teppos/4850733246/
20 / 110
Setup: Create View lockview
21 / 110
Create View lockview1
22 / 110
Create View lockview2
23 / 110
Create and Populate Table lockdemo
24 / 110
Explicit ACCESS SHARE Locking
BEGIN WORK;
BEGIN
25 / 110
Explicit ACCESS SHARE Locking
COMMIT;
COMMIT
26 / 110
Implicit ACCESS SHARE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
27 / 110
Multi-Table ACCESS SHARE Locking
BEGIN WORK;
BEGIN
SELECT pg_class.oid
FROM pg_class JOIN pg_namespace ON (relnamespace = pg_namespace.oid)
JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)
LIMIT 1;
oid
-----
112
(1 row)
28 / 110
Multi-Table ACCESS SHARE Locking
29 / 110
Explicit ROW SHARE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
30 / 110
Implicit ROW SHARE Locking
BEGIN WORK;
BEGIN
SELECT txid_current();
txid_current
--------------
681
(1 row)
31 / 110
Implicit ROW SHARE Locking
COMMIT;
COMMIT
32 / 110
Explicit ROW EXCLUSIVE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
33 / 110
Implicit ROW EXCLUSIVE Locking
BEGIN WORK;
BEGIN
ROLLBACK WORK;
ROLLBACK
34 / 110
Explicit SHARE UPDATE EXCLUSIVE Locking
BEGIN WORK;
BEGIN
LOCK TABLE
(1 row)
COMMIT;
COMMIT
35 / 110
Implicit SHARE UPDATE EXCLUSIVE Locking
BEGIN WORK;
BEGIN
ANALYZE lockdemo;
ANALYZE
(2 rows)
ROLLBACK WORK;
ROLLBACK
36 / 110
Explicit SHARE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
37 / 110
Implicit SHARE Locking
BEGIN WORK;
BEGIN
CREATE INDEX
(4 rows)
COMMIT;
COMMIT
38 / 110
Explicit SHARE ROW EXCLUSIVE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
39 / 110
Implicit SHARE ROW EXCLUSIVE Locking
BEGIN WORK;
BEGIN
ROLLBACK WORK;
ROLLBACK
40 / 110
Explicit EXCLUSIVE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
This lock mode is not automatically used by any Postgres SQL commands.
41 / 110
Explicit ACCESS EXCLUSIVE Locking
BEGIN WORK;
BEGIN
COMMIT;
COMMIT
42 / 110
Implicit ACCESS EXCLUSIVE Locking
BEGIN WORK;
BEGIN
CLUSTER
43 / 110
Implicit ACCESS EXCLUSIVE Locking
COMMIT;
COMMIT
1247 is the pg_class entry for pg_type. 16409 and 16410 are used as
temporary file names.
44 / 110
Lock Examples
45 / 110
Row Locks Are Not Visible in pg_locks
BEGIN WORK;
BEGIN
46 / 110
Two Rows Are Similarly Invisible
COMMIT;
COMMIT
47 / 110
Update Also Causes an Index Lock
BEGIN WORK;
BEGIN
48 / 110
Two Row Updates Are Similar
COMMIT;
COMMIT
49 / 110
Delete of One Row Is Similar
BEGIN WORK;
BEGIN
50 / 110
Delete of Two Rows Is Similar
ROLLBACK WORK;
ROLLBACK
51 / 110
Explicit Row Locks Are Similar
BEGIN WORK;
BEGIN
52 / 110
Three Explicit Row Locks Are Similar
COMMIT;
COMMIT
53 / 110
Explicit Shared Row Locks Are Similar
BEGIN WORK;
BEGIN
54 / 110
Three Explicit Shared Row Locks Are Similar
COMMIT;
COMMIT
55 / 110
Restore Table Lockdemo
56 / 110
UPDATE Is Not Blocked by SELECT
BEGIN WORK;
BEGIN
57 / 110
UPDATE Is Not Blocked by SELECT
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
695
(1 row)
58 / 110
UPDATE Is Not Blocked by SELECT
Required foreground SQL session pg_sleep() calls are not reproduced here, for
clarity.
59 / 110
UPDATE Is Not Blocked by SELECT
COMMIT WORK;
COMMIT
60 / 110
Restore Table Lockdemo
61 / 110
Two Concurrent Updates Show Locking
BEGIN WORK;
BEGIN
62 / 110
Two Concurrent Updates Show Locking
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
699
(1 row)
63 / 110
Two Concurrent Updates Show Locking
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 3; SELECT pg_sleep(0.300); COMMIT; | \
sed s/^/\t/g &
64 / 110
Two Concurrent Updates Show Locking
COMMIT;
COMMIT
65 / 110
Two Concurrent Updates Show Locking
66 / 110
Three Concurrent Updates Show Locking
67 / 110
Three Concurrent Updates Show Locking
lockinfo2 AS (
SELECT pid, vxid, granted, xid_lock, lock_type, relname, page, tuple
FROM lockview
WHERE lock_type = tuple AND
granted
UNION ALL
SELECT lockview.pid, lockview.vxid, lockview.granted, lockview.xid_lock,
lockview.lock_type, lockview.relname, lockview.page, lockview.tuple
FROM lockinfo2 JOIN lockview ON (
lockinfo2.lock_type = lockview.lock_type AND
lockinfo2.relname = lockview.relname AND
lockinfo2.page = lockview.page AND
lockinfo2.tuple = lockview.tuple)
WHERE lockview.lock_type = tuple AND
NOT lockview.granted AND
lockinfo2.granted
)
SELECT * FROM lockinfo1
UNION ALL
SELECT * FROM lockinfo2;
CREATE VIEW
68 / 110
Three Concurrent Updates Show Locking
BEGIN WORK;
BEGIN
69 / 110
Three Concurrent Updates Show Locking
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
702
(1 row)
70 / 110
Three Concurrent Updates Show Locking
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 5; SELECT pg_sleep(0.300); COMMIT; | \
sed s/^/\t/g &
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 6; SELECT pg_sleep(0.300); COMMIT; | \
sed s/^/\t/g &
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 7; SELECT pg_sleep(0.300); COMMIT; | \
sed s/^/\t/g &
71 / 110
Three Concurrent Updates Show Locking
72 / 110
Three Concurrent Updates Show Locking
73 / 110
Three Concurrent Updates Show Locking
74 / 110
Three Concurrent Updates Show Locking
75 / 110
Deadlocks
76 / 110
Deadlocks
BEGIN WORK;
BEGIN
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
710
(1 row)
77 / 110
Deadlocks
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 81 WHERE col = 80; \
UPDATE lockdemo SET col = 51 WHERE col = 50; COMMIT; | sed s/^/\t/g &
78 / 110
Deadlocks
79 / 110
Deadlocks
80 / 110
Deadlocks
81 / 110
Deadlocks
82 / 110
Deadlocks
83 / 110
Deadlocks
COMMIT;
ROLLBACK
84 / 110
Three-Way Deadlocks
85 / 110
Three-Way Deadlocks
BEGIN WORK;
BEGIN
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
714
(1 row)
86 / 110
Three-Way Deadlocks
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 61 WHERE col = 60; \
UPDATE lockdemo SET col = 42 WHERE col = 40; COMMIT; | sed s/^/\t/g &
\! psql -e -c BEGIN WORK; UPDATE lockdemo SET col = 81 WHERE col = 80; \
UPDATE lockdemo SET col = 61 WHERE col = 60; COMMIT; | sed s/^/\t/g &
87 / 110
Three-Way Deadlocks
88 / 110
Three-Way Deadlocks
89 / 110
Three-Way Deadlocks
90 / 110
Three-Way Deadlocks
COMMIT;
COMMIT
91 / 110
Restore Table Lockdemo
92 / 110
Serializable
BEGIN WORK;
BEGIN
93 / 110
Serializable
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
719
(1 row)
94 / 110
Serializable
COMMIT;
COMMIT
95 / 110
Serializable
BEGIN WORK;
BEGIN
96 / 110
Serializable
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
720
(1 row)
97 / 110
Serializable
COMMIT;
COMMIT
98 / 110
Unique Insert Locking
\d lockdemo
Table "public.lockdemo"
Column | Type | Modifiers
--------+---------+-----------
col | integer |
Indexes:
"i_lockdemo" UNIQUE, btree (col) CLUSTER
99 / 110
Unique Insert Locking
BEGIN WORK;
BEGIN
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
721
(1 row)
100 / 110
Unique Insert Locking
ROLLBACK WORK;
ROLLBACK
101 / 110
Subtransactions
BEGIN WORK;
BEGIN
102 / 110
Subtransactions
SAVEPOINT lockdemo1;
SAVEPOINT
103 / 110
Subtransactions
COMMIT;
COMMIT
104 / 110
Advisory Locks
BEGIN WORK;
BEGIN
(1 row)
105 / 110
Advisory Locks
COMMIT;
COMMIT
106 / 110
Joining Pg_locks and Pg_stat_activity
107 / 110
Joining Pg_locks and Pg_stat_activity
BEGIN WORK;
BEGIN
SELECT pg_backend_pid();
pg_backend_pid
----------------
11306
(1 row)
SELECT txid_current();
txid_current
--------------
727
(1 row)
108 / 110
Joining Pg_locks and Pg_stat_activity
(12 rows)
COMMIT;
COMMIT
109 / 110
Conclusion
http://momjian.us/presentations https://www.flickr.com/photos/denisgarciab/
110 / 110