Closed kaaveland closed 7 months ago
add_authors.sql
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.
Started at | Total duration (ms) | Number of dangerous locks |
---|---|---|
2024-05-05T12:16:16.079950952+00:00 | 1005 | 2 ❌ |
Schema | Object | Mode | Relkind | OID | Safe | Duration held (ms) |
---|---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ | 1002 |
public |
books |
AccessShareLock |
Table | 16415 | ✅ | 1002 |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ | 1002 |
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
create table authors(id serial primary key, name text not null);
No locks held at the start of this statement.
No new locks taken by this statement.
alter table books alter column title set not null;
No locks held at the start of this statement.
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
ID: make_column_not_nullable_with_lock
The column title
in the table 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. It is safer to add constraints as NOT VALID
and validate them in later transactions, to avoid holding dangerous locks for a long time. a NOT VALID
constraint will validate all new inserts and updates, but not existing data.
alter table books add column author_id integer not null;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
alter table books add foreign key (author_id) references authors(id);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
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 in a later transaction minimizes time spent holding dangerous locks.
select pg_sleep(1);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
select * from books;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
add_authors.sql
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.
Started at | Total duration (ms) | Number of dangerous locks |
---|---|---|
2024-05-05T12:22:25.673838488+00:00 | 1005 | 2 ❌ |
Schema | Object | Mode | Relkind | OID | Safe | Duration held (ms) |
---|---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books |
AccessShareLock |
Table | 16415 | ✅ | 1002 |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ | 1002 |
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
create table authors(id serial primary key, name text not null);
No locks held at the start of this statement.
No new locks taken by this statement.
alter table books alter column title set not null;
No locks held at the start of this statement.
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
ID: make_column_not_nullable_with_lock
The column title
in the table 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:
CHECK (title IS NOT NULL) NOT VALID;
constraint.
ALTER TABLE ... VALIDATE CONSTRAINT
.alter table books add column author_id integer not null;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
alter table books add foreign key (author_id) references authors(id);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
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 in a later transaction minimizes time spent holding dangerous locks.
select pg_sleep(1);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
No new locks taken by this statement.
select * from books;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
No new locks taken by this statement.
add_authors.sql
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.
Started at | Total duration (ms) | Number of dangerous locks |
---|---|---|
2024-05-05T12:26:08.873830228+00:00 | 1004 | 2 ❌ |
Schema | Object | Mode | Relkind | OID | Safe | Duration held (ms) |
---|---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books |
AccessShareLock |
Table | 16415 | ✅ | 1002 |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ | 1002 |
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
create table authors(id serial primary key, name text not null);
No locks held at the start of this statement.
No new locks taken by this statement.
alter table books alter column title set not null;
No locks held at the start of this statement.
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
NOT NULL
columnID: make_column_not_nullable_with_lock
The column title
in the table 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:
CHECK (title IS NOT NULL) NOT VALID;
constraint.
ALTER TABLE ... VALIDATE CONSTRAINT
.NOT NULL
alter table books add column author_id integer not null;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
alter table books add foreign key (author_id) references authors(id);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
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.
select pg_sleep(1);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
No new locks taken by this statement.
select * from books;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
No new locks taken by this statement.
add_authors.sql
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.
Started at | Total duration (ms) | Number of dangerous locks |
---|---|---|
2024-05-05T12:30:32.901945792+00:00 | 1006 | 2 ❌ |
Schema | Object | Mode | Relkind | OID | Safe | Duration held (ms) |
---|---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ | 1002 |
public |
books |
AccessShareLock |
Table | 16415 | ✅ | 1002 |
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
create table authors(id serial primary key, name text not null);
No locks held at the start of this statement.
No new locks taken by this statement.
alter table books alter column title set not null;
No locks held at the start of this statement.
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
NOT NULL
columnID: make_column_not_nullable_with_lock
The column title
in the table 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:
CHECK (title IS NOT NULL) NOT VALID;
constraint.
ALTER TABLE ... VALIDATE CONSTRAINT
.NOT NULL
alter table books add column author_id integer not null;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
. This lock blocks all other transactions from accessing the database object. Once holding AccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
alter table books add foreign key (author_id) references authors(id);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
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.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
. This lock blocks all other transactions from accessing the database object. Once holding AccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
select pg_sleep(1);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
No new locks taken by this statement.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
. This lock blocks all other transactions from accessing the database object. Once holding AccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
select * from books;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
No new locks taken by this statement.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
. This lock blocks all other transactions from accessing the database object. Once holding AccessExclusiveLock
we should immediately commit the transaction. Any extra steps necessary are better done in a separate transaction.
add_authors.sql
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.
Started at | Total duration (ms) | Number of dangerous locks |
---|---|---|
2024-05-05T12:42:16.002982811+00:00 | 1005 | 2 ❌ |
Schema | Object | Mode | Relkind | OID | Safe | Duration held (ms) |
---|---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ | 1002 |
public |
books |
AccessShareLock |
Table | 16415 | ✅ | 1002 |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ | 1002 |
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
create table authors(id serial primary key, name text not null);
No locks held at the start of this statement.
No new locks taken by this statement.
alter table books alter column title set not null;
No locks held at the start of this statement.
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
NOT NULL
columnID: make_column_not_nullable_with_lock
The column title
in the table 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:
CHECK (title IS NOT NULL) NOT VALID;
constraint.
ALTER TABLE ... VALIDATE CONSTRAINT
.NOT NULL
alter table books add column author_id integer not null;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
, 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.
alter table books add foreign key (author_id) references authors(id);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
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.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
, 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.
select pg_sleep(1);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
, 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.
select * from books;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
AccessExclusiveLock
ID: holding_access_exclusive
The statement is running while holding an AccessExclusiveLock
on the Table books
, 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.
add_authors.sql
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.
Started at | Total duration (ms) | Number of dangerous locks |
---|---|---|
2024-05-05T12:48:09.234165630+00:00 | 1005 | 2 ❌ |
Schema | Object | Mode | Relkind | OID | Safe | Duration held (ms) |
---|---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ | 1002 |
public |
books |
AccessShareLock |
Table | 16415 | ✅ | 1002 |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ | 1002 |
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
create table authors(id serial primary key, name text not null);
No locks held at the start of this statement.
No new locks taken by this statement.
alter table books alter column title set not null;
No locks held at the start of this statement.
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
NOT NULL
columnID: 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:
CHECK (title IS NOT NULL) NOT VALID;
constraint.
ALTER TABLE ... VALIDATE CONSTRAINT
.NOT NULL
alter table books add column author_id integer not null;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
No new locks taken by this statement.
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.
alter table books add foreign key (author_id) references authors(id);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
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.
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.
select pg_sleep(1);
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
No new locks taken by this statement.
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.
select * from books;
Schema | Object | Mode | Relkind | OID | Safe |
---|---|---|---|---|---|
public |
books |
AccessExclusiveLock |
Table | 16415 | ❌ |
public |
books |
ShareRowExclusiveLock |
Table | 16415 | ❌ |
public |
books |
AccessShareLock |
Table | 16415 | ✅ |
public |
books_pkey |
AccessShareLock |
Index | 16421 | ✅ |
No new locks taken by this statement.
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
ShareRowExclusiveLock
public
books_pkey
AccessShareLock
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 column
ID:
make_column_not_nullable_with_lock
The column
title
in the tablebooks
was changed toNOT NULL
. The statement blocks until all rows in the table are validated to beNOT NULL
, unless a CHECK (title IS NOT NULL) constraint exists, in which case it is safe. It is safer to add constraints asNOT VALID
and validate them in later transactions, to avoid holding dangerous locks for a long time. aNOT VALID
constraint will validate all new inserts and updates, but not existing data.Statement number 3 for 0 ms
SQL
Locks at start
public
books
AccessExclusiveLock
New locks taken
No new locks taken by this statement.
Statement number 4 for 0 ms
SQL
Locks at start
public
books
AccessExclusiveLock
New locks taken
public
books
AccessShareLock
public
books
ShareRowExclusiveLock
public
books_pkey
AccessShareLock
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 in a later transaction minimizes time spent holding dangerous locks.Statement number 5 for 1001 ms
SQL
Locks at start
public
books
AccessExclusiveLock
public
books
AccessShareLock
public
books
ShareRowExclusiveLock
public
books_pkey
AccessShareLock
New locks taken
No new locks taken by this statement.
Statement number 6 for 0 ms
SQL
Locks at start
public
books
AccessExclusiveLock
public
books
AccessShareLock
public
books
ShareRowExclusiveLock
public
books_pkey
AccessShareLock
New locks taken
No new locks taken by this statement.