In the below trace, a lock is considered dangerous if it conflicts with application code queries, such as SELECT or INSERT.
We should aim to hold dangerous locks for as little time as possible. If a dangerous lock is held while doing an operation that does not require it, we should split the migration into two steps.
For example, it often will make sense to add a new column in one migration, then backfill it in a separate one, since adding a column requires an AccessExclusiveLock while backfilling can do with a RowExclusiveLock which is much less likely to block concurrent transactions.
Overall Summary
Started at
Total duration (ms)
Number of dangerous locks
2024-05-05T13:52:54.349625615+00:00
1003
2 ❌
All locks acquired
Schema
Object
Mode
Relkind
OID
Safe
Duration held (ms)
public
books
AccessExclusiveLock
Table
16415
❌
1000
public
books
AccessShareLock
Table
16415
✅
1000
public
books_pkey
AccessShareLock
Index
16421
✅
1000
public
books
ShareRowExclusiveLock
Table
16415
❌
1000
Dangerous locks found
AccessExclusiveLock would block the following operations on public.books:
SELECT
FOR UPDATE
FOR NO KEY UPDATE
FOR SHARE
FOR KEY SHARE
UPDATE
DELETE
INSERT
MERGE
ShareRowExclusiveLock would block the following operations on public.books:
UPDATE
DELETE
INSERT
MERGE
Statement number 1 for 3 ms
SQL
create table authors(id serial primary key, name text not null);
Locks at start
No locks held at the start of this statement.
New locks taken
No new locks taken by this statement.
Statement number 2 for 0 ms
SQL
alter table books alter column title set not null;
Locks at start
No locks held at the start of this statement.
New locks taken
Schema
Object
Mode
Relkind
OID
Safe
public
books
AccessExclusiveLock
Table
16415
❌
Hints
Validating table with a new NOT NULL column
ID: make_column_not_nullable_with_lock
The column title in the table public.books was changed to NOT NULL. The statement blocks until all rows in the table are validated to be NOT NULL, unless a CHECK (title IS NOT NULL) constraint exists, in which case it is safe. Split this type of change into steps:
Add a CHECK (title IS NOT NULL) NOT VALID; constraint.
Validate the constraint in a later transaction, with ALTER TABLE ... VALIDATE CONSTRAINT.
Make the column NOT NULL
Statement number 3 for 0 ms
SQL
alter table books add column author_id integer not null;
Locks at start
Schema
Object
Mode
Relkind
OID
Safe
public
books
AccessExclusiveLock
Table
16415
❌
New locks taken
No new locks taken by this statement.
Hints
Running more statements after taking AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock on the Table publicbooks, blocking all other transactions from accessing it. Once holding AccessExclusiveLock we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
Statement number 4 for 0 ms
SQL
alter table books add foreign key (author_id) references authors(id);
Locks at start
Schema
Object
Mode
Relkind
OID
Safe
public
books
AccessExclusiveLock
Table
16415
❌
New locks taken
Schema
Object
Mode
Relkind
OID
Safe
public
books
AccessShareLock
Table
16415
✅
public
books_pkey
AccessShareLock
Index
16421
✅
public
books
ShareRowExclusiveLock
Table
16415
❌
Hints
Validating table with a new constraint
ID: validate_constraint_with_lock
A new constraint books_author_id_fkey was added to the table books. The constraint is of type FOREIGN KEY and is valid. The statement blocks until all rows in the table are validated for the constraint. It is safer to add constraints as NOT VALID and validate them later, to avoid holding dangerous locks for a long time. Constraints that are NOT VALID affect all new inserts and updates, but not existing data. Adding the constraint initially as NOT VALID, then validating with ALTER TABLE ... VALIDATE CONSTRAINT ... in a later transaction minimizes time spent holding dangerous locks.
Running more statements after taking AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock on the Table publicbooks, blocking all other transactions from accessing it. Once holding AccessExclusiveLock we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
Statement number 5 for 1000 ms
SQL
select pg_sleep(1);
Locks at start
Schema
Object
Mode
Relkind
OID
Safe
public
books
AccessExclusiveLock
Table
16415
❌
public
books
AccessShareLock
Table
16415
✅
public
books_pkey
AccessShareLock
Index
16421
✅
public
books
ShareRowExclusiveLock
Table
16415
❌
New locks taken
No new locks taken by this statement.
Hints
Running more statements after taking AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock on the Table publicbooks, blocking all other transactions from accessing it. Once holding AccessExclusiveLock we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
Statement number 6 for 0 ms
SQL
select * from books;
Locks at start
Schema
Object
Mode
Relkind
OID
Safe
public
books
AccessExclusiveLock
Table
16415
❌
public
books
AccessShareLock
Table
16415
✅
public
books_pkey
AccessShareLock
Index
16421
✅
public
books
ShareRowExclusiveLock
Table
16415
❌
New locks taken
No new locks taken by this statement.
Hints
Running more statements after taking AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock on the Table publicbooks, blocking all other transactions from accessing it. Once holding AccessExclusiveLock we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
Eugene 🔒 trace of
add_authors.sql
In the below trace, a lock is considered dangerous if it conflicts with application code queries, such as
SELECT
orINSERT
.We should aim to hold dangerous locks for as little time as possible. If a dangerous lock is held while doing an operation that does not require it, we should split the migration into two steps.
For example, it often will make sense to add a new column in one migration, then backfill it in a separate one, since adding a column requires an
AccessExclusiveLock
while backfilling can do with aRowExclusiveLock
which is much less likely to block concurrent transactions.Overall Summary
All locks acquired
public
books
AccessExclusiveLock
public
books
AccessShareLock
public
books_pkey
AccessShareLock
public
books
ShareRowExclusiveLock
Dangerous locks found
AccessExclusiveLock
would block the following operations onpublic.books
:SELECT
FOR UPDATE
FOR NO KEY UPDATE
FOR SHARE
FOR KEY SHARE
UPDATE
DELETE
INSERT
MERGE
ShareRowExclusiveLock
would block the following operations onpublic.books
:UPDATE
DELETE
INSERT
MERGE
Statement number 1 for 3 ms
SQL
Locks at start
No locks held at the start of this statement.
New locks taken
No new locks taken by this statement.
Statement number 2 for 0 ms
SQL
Locks at start
No locks held at the start of this statement.
New locks taken
public
books
AccessExclusiveLock
Hints
Validating table with a new
NOT NULL
columnID:
make_column_not_nullable_with_lock
The column
title
in the tablepublic.books
was changed toNOT NULL
. The statement blocks until all rows in the table are validated to beNOT NULL
, unless aCHECK (title IS NOT NULL)
constraint exists, in which case it is safe. Split this type of change into steps:CHECK (title IS NOT NULL) NOT VALID;
constraint.ALTER TABLE ... VALIDATE CONSTRAINT
.NOT NULL
Statement number 3 for 0 ms
SQL
Locks at start
public
books
AccessExclusiveLock
New locks taken
No new locks taken by this statement.
Hints
Running more statements after taking
AccessExclusiveLock
ID:
holding_access_exclusive
The statement is running while holding an
AccessExclusiveLock
on the Tablepublicbooks
, blocking all other transactions from accessing it. Once holdingAccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.Statement number 4 for 0 ms
SQL
Locks at start
public
books
AccessExclusiveLock
New locks taken
public
books
AccessShareLock
public
books_pkey
AccessShareLock
public
books
ShareRowExclusiveLock
Hints
Validating table with a new constraint
ID:
validate_constraint_with_lock
A new constraint
books_author_id_fkey
was added to the tablebooks
. The constraint is of typeFOREIGN KEY
and is valid. The statement blocks until all rows in the table are validated for the constraint. It is safer to add constraints asNOT VALID
and validate them later, to avoid holding dangerous locks for a long time. Constraints that areNOT VALID
affect all new inserts and updates, but not existing data. Adding the constraint initially asNOT VALID
, then validating withALTER TABLE ... VALIDATE CONSTRAINT ...
in a later transaction minimizes time spent holding dangerous locks.Running more statements after taking
AccessExclusiveLock
ID:
holding_access_exclusive
The statement is running while holding an
AccessExclusiveLock
on the Tablepublicbooks
, blocking all other transactions from accessing it. Once holdingAccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.Statement number 5 for 1000 ms
SQL
Locks at start
public
books
AccessExclusiveLock
public
books
AccessShareLock
public
books_pkey
AccessShareLock
public
books
ShareRowExclusiveLock
New locks taken
No new locks taken by this statement.
Hints
Running more statements after taking
AccessExclusiveLock
ID:
holding_access_exclusive
The statement is running while holding an
AccessExclusiveLock
on the Tablepublicbooks
, blocking all other transactions from accessing it. Once holdingAccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.Statement number 6 for 0 ms
SQL
Locks at start
public
books
AccessExclusiveLock
public
books
AccessShareLock
public
books_pkey
AccessShareLock
public
books
ShareRowExclusiveLock
New locks taken
No new locks taken by this statement.
Hints
Running more statements after taking
AccessExclusiveLock
ID:
holding_access_exclusive
The statement is running while holding an
AccessExclusiveLock
on the Tablepublicbooks
, blocking all other transactions from accessing it. Once holdingAccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.