Skip to content

clarify isolation level upgrades #19490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/current/_includes/v23.2/sql/isolation-levels.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Isolation is an element of [ACID transactions](https://en.wikipedia.org/wiki/ACID) that determines how concurrency is controlled, and ultimately guarantees consistency. CockroachDB offers two transaction isolation levels: [`SERIALIZABLE`]({% link {{ page.version.version }}/demo-serializable.md %}) and [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}).

By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}). For a demonstration of how `SERIALIZABLE` prevents write skew anomalies, see [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).
By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, refer to [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).

{% include_cached new-in.html version="v23.2" %} CockroachDB can be configured to execute transactions at [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}) instead of `SERIALIZABLE` isolation. If [enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation), `READ COMMITTED` is no longer an alias for `SERIALIZABLE` . `READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and [retries]({% link {{ page.version.version }}/developer-basics.md %}#transaction-retries). Depending on your workload requirements, this may be desirable. For more information, see [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).
{% include_cached new-in.html version="v23.2" %} CockroachDB can be configured to execute transactions at [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}) instead of `SERIALIZABLE` isolation. If [enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation), `READ COMMITTED` and `READ UNCOMMITTED` transactions no longer [upgrade to `SERIALIZABLE`]({% link {{ page.version.version }}/transactions.md %}#isolation-level-upgrades). `READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and [retries]({% link {{ page.version.version }}/developer-basics.md %}#transaction-retries). Depending on your workload requirements, this may be desirable. For more information, refer to [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).

{% include {{ page.version.version }}/sql/mixed-isolation-levels.md %}
4 changes: 2 additions & 2 deletions src/current/_includes/v24.1/sql/isolation-levels.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Isolation is an element of [ACID transactions](https://en.wikipedia.org/wiki/ACID) that determines how concurrency is controlled, and ultimately guarantees consistency. CockroachDB offers two transaction isolation levels: [`SERIALIZABLE`]({% link {{ page.version.version }}/demo-serializable.md %}) and [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}).

By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, see [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).
By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, refer to [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).

CockroachDB can be configured to execute transactions at [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}) instead of `SERIALIZABLE` isolation. If [enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation), `READ COMMITTED` is no longer an alias for `SERIALIZABLE` . `READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, see [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).
`READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, refer to [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).

{% include {{ page.version.version }}/sql/mixed-isolation-levels.md %}
4 changes: 2 additions & 2 deletions src/current/_includes/v24.2/sql/isolation-levels.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Isolation is an element of [ACID transactions](https://en.wikipedia.org/wiki/ACID) that determines how concurrency is controlled, and ultimately guarantees consistency. CockroachDB offers two transaction isolation levels: [`SERIALIZABLE`]({% link {{ page.version.version }}/demo-serializable.md %}) and [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}).

By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, see [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).
By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, refer to [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).

CockroachDB can be configured to execute transactions at [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}) instead of `SERIALIZABLE` isolation. If [enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation), `READ COMMITTED` is no longer an alias for `SERIALIZABLE` . `READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, see [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).
`READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, refer to [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).

{% include {{ page.version.version }}/sql/mixed-isolation-levels.md %}
4 changes: 2 additions & 2 deletions src/current/_includes/v24.3/sql/isolation-levels.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Isolation is an element of [ACID transactions](https://en.wikipedia.org/wiki/ACID) that determines how concurrency is controlled, and ultimately guarantees consistency. CockroachDB offers two transaction isolation levels: [`SERIALIZABLE`]({% link {{ page.version.version }}/demo-serializable.md %}) and [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}).

By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, see [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).
By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, refer to [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).

CockroachDB can be configured to execute transactions at [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}) instead of `SERIALIZABLE` isolation. If [enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation), `READ COMMITTED` is no longer an alias for `SERIALIZABLE` . `READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, see [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).
`READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, refer to [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).

{% include {{ page.version.version }}/sql/mixed-isolation-levels.md %}
4 changes: 2 additions & 2 deletions src/current/_includes/v25.1/sql/isolation-levels.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Isolation is an element of [ACID transactions](https://en.wikipedia.org/wiki/ACID) that determines how concurrency is controlled, and ultimately guarantees consistency. CockroachDB offers two transaction isolation levels: [`SERIALIZABLE`]({% link {{ page.version.version }}/demo-serializable.md %}) and [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}).

By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, see [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).
By default, CockroachDB executes all transactions at the strongest ANSI transaction isolation level: `SERIALIZABLE`, which permits no concurrency anomalies. To place all transactions in a serializable ordering, `SERIALIZABLE` isolation may require [transaction restarts]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) and [client-side retry handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling). For a demonstration of how `SERIALIZABLE` prevents anomalies such as write skew, refer to [Serializable Transactions]({% link {{ page.version.version }}/demo-serializable.md %}).

CockroachDB can be configured to execute transactions at [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %}) instead of `SERIALIZABLE` isolation. If [enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation), `READ COMMITTED` is no longer an alias for `SERIALIZABLE` . `READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, see [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).
`READ COMMITTED` permits some concurrency anomalies in exchange for minimizing transaction aborts and removing the need for client-side retries. Depending on your workload requirements, this may be desirable. For more information, refer to [Read Committed Transactions]({% link {{ page.version.version }}/read-committed.md %}).

{% include {{ page.version.version }}/sql/mixed-isolation-levels.md %}
30 changes: 22 additions & 8 deletions src/current/v23.2/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,23 +206,37 @@ To view the current priority of a transaction, use `SHOW transaction_priority` o

{% include {{ page.version.version }}/sql/isolation-levels.md %}

### Comparison to ANSI SQL isolation levels
### Isolation level upgrades

CockroachDB uses slightly different isolation levels than [ANSI SQL isolation levels](https://wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels).
By default, CockroachDB executes all transactions at `SERIALIZABLE` isolation. Under certain conditions, transactions issued at weaker isolation levels are automatically upgraded to stronger isolation levels.

If `sql.txn.read_committed_isolation.enabled` is set to `true` ([enabling `READ COMMITTED` isolation]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation)):

#### Aliases
| Isolation level | Upgrades to |
|--------------------|------------------|
| `READ UNCOMMITTED` | `READ COMMITTED` |
| `READ COMMITTED` | -- |
| `REPEATABLE READ` | `SNAPSHOT` |
| `SNAPSHOT` | `SERIALIZABLE` |
| `SERIALIZABLE` | -- |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Sorry, this is bikeshedding, you can ignore this comment unless you feel convinced 🙂.)

This table isn't incorrect, but IMO the REPEATABLE READ -> SNAPSHOT -> SERIALIZABLE upgrade chain idea is a little confusing and puts more emphasis on "upgrades" than I think they're worth.

If I were writing this I think I would say first (or last) that READ UNCOMMITTED is an alias for READ COMMITTED and REPEATABLE READ is an alias for SNAPSHOT and then I wouldn't mention those levels again. And then I would only describe the upgrades in terms of READ COMMITTED, SNAPSHOT, and SERIALIZABLE, which are the three "real" isolation levels we support. I think that would put the emphasis in the right place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! The reason I thought to highlight READ UNCOMMITTED as an 'upgrade' to READ COMMITTED is because the Upgrades to SQL Isolation Level chart seems to track that exact 'upgrade,' which became part of a customer issue recently. That's why I've been confused about "alias" vs "upgrade". cc @rafiss

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for explaining. Now I understand.

From some experimentation, looks like:

  • READ UNCOMMITTED -> READ COMMITTED does increment the metric
  • REPEATABLE READ -> SNAPSHOT does not increment the metric
  • READ COMMITTED -> SERIALIZABLE does increment the metric
  • SNAPSHOT -> SERIALIZABLE does increment the metric

So I guess only REPEATABLE READ could be considered an alias for SNAPSHOT, and the rest are upgrades?

Here's how I figured that out:

[email protected]:26257/demoapp/defaultdb> \set show_times=false
[email protected]:26257/demoapp/defaultdb> SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = true;
SET CLUSTER SETTING
[email protected]:26257/demoapp/defaultdb> SELECT DISTINCT variable, value FROM [SHOW ALL CLUSTER SETTINGS] WHERE variable LIKE '%isolation%';
                  variable                  | value
--------------------------------------------+--------
  sql.txn.read_committed_isolation.enabled  | true
  sql.txn.repeatable_read_isolation.enabled | true
(2 rows)
[email protected]:26257/demoapp/defaultdb> SELECT * FROM crdb_internal.node_metrics WHERE name LIKE '%iso_level%' ORDER BY name;
  store_id |                   name                    | value
-----------+-------------------------------------------+--------
      NULL | sql.txn.upgraded_iso_level.count          |     0
      NULL | sql.txn.upgraded_iso_level.count.internal |     0
(2 rows)
[email protected]:26257/demoapp/defaultdb> BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; EXPLAIN ANALYZE SELECT 1; COMMIT;
BEGIN
                   info
-------------------------------------------
  planning time: 332µs
  execution time: 357µs
  distribution: local
  vectorized: true
  plan type: custom
  maximum memory usage: 10 KiB
  DistSQL network usage: 0 B (0 messages)
  regions: us-east1
  sql cpu time: 50µs
  estimated RUs consumed: 0
  isolation level: read committed
  priority: normal
  quality of service: regular

  • values
    sql nodes: n1
    regions: us-east1
    actual row count: 1
    execution time: 49µs
    sql cpu time: 50µs
    size: 1 column, 1 row
(21 rows)
COMMIT
[email protected]:26257/demoapp/defaultdb> SELECT * FROM crdb_internal.node_metrics WHERE name LIKE '%iso_level%' ORDER BY name;
  store_id |                   name                    | value
-----------+-------------------------------------------+--------
      NULL | sql.txn.upgraded_iso_level.count          |     1
      NULL | sql.txn.upgraded_iso_level.count.internal |     0
(2 rows)
[email protected]:26257/demoapp/defaultdb> BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; EXPLAIN ANALYZE SELECT 1; COMMIT;
BEGIN
                   info
-------------------------------------------
  planning time: 263µs
  execution time: 272µs
  distribution: local
  vectorized: true
  plan type: generic, re-optimized
  maximum memory usage: 10 KiB
  DistSQL network usage: 0 B (0 messages)
  regions: us-east1
  sql cpu time: 46µs
  estimated RUs consumed: 0
  isolation level: snapshot
  priority: normal
  quality of service: regular

  • values
    sql nodes: n1
    regions: us-east1
    actual row count: 1
    execution time: 46µs
    sql cpu time: 46µs
    size: 1 column, 1 row
(21 rows)
COMMIT
[email protected]:26257/demoapp/defaultdb> SELECT * FROM crdb_internal.node_metrics WHERE name LIKE '%iso_level%' ORDER BY name;
  store_id |                   name                    | value
-----------+-------------------------------------------+--------
      NULL | sql.txn.upgraded_iso_level.count          |     1
      NULL | sql.txn.upgraded_iso_level.count.internal |     0
(2 rows)
[email protected]:26257/demoapp/defaultdb> SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = false;
SET CLUSTER SETTING
[email protected]:26257/demoapp/defaultdb> SET CLUSTER SETTING sql.txn.read_committed_isolation.enabled = false;
SET CLUSTER SETTING
[email protected]:26257/demoapp/defaultdb> SELECT DISTINCT variable, value FROM [SHOW ALL CLUSTER SETTINGS] WHERE variable LIKE '%isolation%';
                  variable                  | value
--------------------------------------------+--------
  sql.txn.read_committed_isolation.enabled  | false
  sql.txn.repeatable_read_isolation.enabled | false
(2 rows)
[email protected]:26257/demoapp/defaultdb> BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; EXPLAIN ANALYZE SELECT 1; COMMIT;
BEGIN
                   info
-------------------------------------------
  planning time: 349µs
  execution time: 362µs
  distribution: local
  vectorized: true
  plan type: generic, re-optimized
  maximum memory usage: 10 KiB
  DistSQL network usage: 0 B (0 messages)
  regions: us-east1
  sql cpu time: 67µs
  estimated RUs consumed: 0
  isolation level: serializable
  priority: normal
  quality of service: regular

  • values
    sql nodes: n1
    regions: us-east1
    actual row count: 1
    execution time: 67µs
    sql cpu time: 67µs
    size: 1 column, 1 row
(21 rows)
COMMIT
[email protected]:26257/demoapp/defaultdb> SELECT * FROM crdb_internal.node_metrics WHERE name LIKE '%iso_level%' ORDER BY name;
  store_id |                   name                    | value
-----------+-------------------------------------------+--------
      NULL | sql.txn.upgraded_iso_level.count          |     2
      NULL | sql.txn.upgraded_iso_level.count.internal |     0
(2 rows)
[email protected]:26257/demoapp/defaultdb> BEGIN TRANSACTION ISOLATION LEVEL SNAPSHOT; EXPLAIN ANALYZE SELECT 1; COMMIT;
BEGIN
                   info
-------------------------------------------
  planning time: 81µs
  execution time: 148µs
  distribution: local
  vectorized: true
  plan type: generic, reused
  maximum memory usage: 10 KiB
  DistSQL network usage: 0 B (0 messages)
  regions: us-east1
  sql cpu time: 24µs
  estimated RUs consumed: 0
  isolation level: serializable
  priority: normal
  quality of service: regular

  • values
    sql nodes: n1
    regions: us-east1
    actual row count: 1
    execution time: 24µs
    sql cpu time: 24µs
    size: 1 column, 1 row
(21 rows)
COMMIT
[email protected]:26257/demoapp/defaultdb> SELECT * FROM crdb_internal.node_metrics WHERE name LIKE '%iso_level%' ORDER BY name;
  store_id |                   name                    | value
-----------+-------------------------------------------+--------
      NULL | sql.txn.upgraded_iso_level.count          |     3
      NULL | sql.txn.upgraded_iso_level.count.internal |     0
(2 rows)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, let's treat READ UNCOMMITTED -> READ COMMITTED as an upgrade of the isolation level, since they are clearly defined as different levels in PG docs and in the SQL standard.

And also +1 to treating SNAPSHOT and REPEATABLE READ as pure aliases of each other. However, the caveat with this is that this isolation level is not enabled by default. It's gated behind the cluster setting sql.txn.repeatable_read_isolation.enabled, which defaults to false (and this setting also has an alias sql.txn.snapshot_isolation.enabled). I'm just pointing this out in case we want to mention that setting here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, i see the setting is mentioned already. lgtm!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind, i got myself confused again. the current PR mentions sql.txn.read_committed_isolation.enabled which is true by default, but not sql.txn.repeatable_read_isolation.enabled which is false by default. given that we don't really mention repeatable read anywhere else in the docs, i'm not really sure how we want to discuss it here. i recall @dikshant mentioning he wanted to wait a bit before advertising that we support it (https://cockroachlabs.slack.com/archives/C051DMXEGMV/p1733255496192269?thread_ts=1733251940.956479&cid=C051DMXEGMV)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense -- I'm removing the row with REPEATABLE READ but leaving the one with SNAPSHOT.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of the product decision to not mention REPEATABLE READ here, the same concerns would apply to mentioning SNAPSHOT. The usage of either of them is gated behind the sql.txn.repeatable_read_isolation.enabled/sql.txn.snapshot_isolation.enabled cluster setting, which are aliases of each other.

Copy link
Contributor Author

@taroface taroface Apr 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, got it! Amending.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Yeah good to leave out repeatable read for now.


`SNAPSHOT`, `READ UNCOMMITTED`, `READ COMMITTED`, and `REPEATABLE READ` are aliases for `SERIALIZABLE`.
{{site.data.alerts.callout_info}}
In this configuration, `REPEATABLE READ` effectively upgrades to `SERIALIZABLE`.
{{site.data.alerts.end}}

{% include_cached new-in.html version="v23.2" %} If [`READ COMMITTED` isolation is enabled]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation) using the `sql.txn.read_committed_isolation.enabled` [cluster setting]({% link {{ page.version.version }}/cluster-settings.md %}), `READ COMMITTED` is no longer an alias for `SERIALIZABLE`, and `READ UNCOMMITTED` becomes an alias for `READ COMMITTED`.
If `sql.txn.read_committed_isolation.enabled` is set to `false` (disabling `READ COMMITTED` isolation), all isolation levels upgrade to `SERIALIZABLE`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: It might be clearer to make "transactions" the subject of the sentence rather than "isolation levels", something like:

If sql.txn.read_committed_isolation.enabled is set to false (disabling READ COMMITTED isolation), all transactions run under SERIALIZABLE isolation regardless of the isolation level requested.


#### Comparison
If a transaction includes [DDL]({% link {{ page.version.version }}/sql-statements.md %}#data-definition-statements) or [`AOST`]({% link {{ page.version.version }}/as-of-system-time.md %}) statements, all isolation levels upgrade to `SERIALIZABLE`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I played around with this a bit, and I think we should not say anything about AOST. I believe the upgrade to serializable behavior for AOST transactions happens entirely in the KV layer. The SQL layer still considers AOST transactions to have read committed isolation, so it probably just confuses things to say they're upgraded.

@rafiss is this correct about DDL? Do we silently commit the transaction and start a new one for DDL?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with not mentioning AOST here.

As for DDL, yes that's correct, we will upgrade the transaction to SERIALIZABLE if possible -- meaning as long as the transaction hasn't performed any work yet, it will be upgraded. (https://github.com/cockroachdb/cockroach/blob/3acb6e287300ad4df232e2e4028af2f2435c5220/pkg/sql/conn_executor_ddl.go#L76)

Let's not mention autocommit behavior around DDLs here though. That's a separate piece of functionality, controlled by the autocommit_before_ddl setting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks both for clarifying these points. I'm just going to avoid talking about AOST and DDL txns altogether, since we have this open issue that could update the behavior again at some point.


### Comparison to ANSI SQL isolation levels

CockroachDB uses slightly different isolation levels than [ANSI SQL isolation levels](https://wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels).

The CockroachDB `SERIALIZABLE` isolation level is stronger than the ANSI SQL `READ UNCOMMITTED`, `READ COMMITTED`, and `REPEATABLE READ` levels and equivalent to the ANSI SQL `SERIALIZABLE` level.
The CockroachDB `SERIALIZABLE` isolation level is stronger than the ANSI SQL `READ UNCOMMITTED`, `READ COMMITTED`, and `REPEATABLE READ` levels, as well as the `SNAPSHOT` level. It is equivalent to the ANSI SQL `SERIALIZABLE` level.

The CockroachDB `READ COMMITTED` isolation level is stronger than the PostgreSQL `READ COMMITTED` isolation level, and is the strongest isolation level that does not experience [serialization errors]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}) that require [client-side handling]({% link {{ page.version.version }}/transaction-retry-error-reference.md %}#client-side-retry-handling).

For more information about the relationship between these levels, see [A Critique of ANSI SQL Isolation Levels](https://arxiv.org/ftp/cs/papers/0701/0701157.pdf).
For more information about the relationship between these levels, read [A Critique of ANSI SQL Isolation Levels](https://arxiv.org/ftp/cs/papers/0701/0701157.pdf).

## Limit the number of rows written or read in a transaction

Expand Down
2 changes: 1 addition & 1 deletion src/current/v23.2/ui-sql-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The **SQL Connection Rate** is an average of the number of connection attempts p

- In the cluster view, the graph shows the total number of times a SQL transaction was upgraded to a stronger isolation level across all nodes.

If this metric is non-zero, then transactions at weaker isolation levels (such as [`READ COMMITTED`]({% link {{ page.version.version }}/read-committed.md %})) are being upgraded to [`SERIALIZABLE`]({% link {{ page.version.version }}/demo-serializable.md %}) instead. To ensure that `READ COMMITTED` transactions run as `READ COMMITTED`, see [Enable `READ COMMITTED` isolation]({% link {{ page.version.version }}/read-committed.md %}#enable-read-committed-isolation).
If this metric is non-zero, then transactions are being [upgraded to stronger isolation levels]({% link {{ page.version.version }}/transactions.md %}#isolation-level-upgrades).

## Open SQL Transactions

Expand Down
Loading
Loading