Skip to content

Commit a07b2ad

Browse files
committed
Update docs to recommend UUIDv4 explicitly
Fixes DOC-9482
1 parent f87dd09 commit a07b2ad

13 files changed

+46
-22
lines changed

src/current/_includes/v25.3/faq/auto-generate-unique-ids.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
To auto-generate unique row identifiers, you can use the `gen_random_uuid()`, `uuid_v4()`, or `unique_rowid()` [functions]({% link {{ page.version.version }}/functions-and-operators.md %}#id-generation-functions).
1+
To auto-generate unique row identifiers, you can use the following [functions]({% link {{ page.version.version }}/functions-and-operators.md %}#id-generation-functions):
2+
3+
- [Use `gen_random_uuid()`](#use-gen_random_uuid): Generates a UUIDv4 with `UUID` data type.
4+
- [Use `uuid_v4()`](#use-uuid_v4): Generates a UUIDv4 with `BYTES` data type.
5+
- [Use `unique_rowid()`](#use-unique_rowid): Generates a globally unique `INT` data type
6+
7+
{{site.data.alerts.callout_success}}
8+
{% include {{ page.version.version }}/sql/use-uuidv4.md %}
9+
{{site.data.alerts.end}}
10+
11+
#### Use `gen_random_uuid()`
212

313
To use the [`UUID`]({% link {{ page.version.version }}/uuid.md %}) column with the `gen_random_uuid()` [function]({% link {{ page.version.version }}/functions-and-operators.md %}#id-generation-functions) as the [default value]({% link {{ page.version.version }}/default-value.md %}):
414

@@ -34,6 +44,8 @@ SELECT * FROM users;
3444
(3 rows)
3545
~~~
3646

47+
#### Use `uuid_v4()`
48+
3749
Alternatively, you can use the [`BYTES`]({% link {{ page.version.version }}/bytes.md %}) column with the `uuid_v4()` function as the default value:
3850

3951
{% include_cached copy-clipboard.html %}
@@ -72,6 +84,8 @@ In either case, generated IDs will be 128-bit, sufficiently large to generate un
7284

7385
This approach has the disadvantage of creating a primary key that may not be useful in a query directly, which can require a join with another table or a secondary index.
7486

87+
#### Use `unique_rowid()`
88+
7589
If it is important for generated IDs to be stored in the same key-value range, you can use an [integer type]({% link {{ page.version.version }}/int.md %}) with the `unique_rowid()` [function]({% link {{ page.version.version }}/functions-and-operators.md %}#id-generation-functions) as the default value, either explicitly or via the [`SERIAL` pseudo-type]({% link {{ page.version.version }}/serial.md %}):
7690

7791
{% include_cached copy-clipboard.html %}

src/current/_includes/v25.3/faq/differences-between-numberings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
| Property | UUID generated with `uuid_v4()` | INT generated with `unique_rowid()` | Sequences |
2+
| Property | [UUID]({% link {{ page.version.version }}/uuid.md %}) generated with `uuid_v4()` | INT generated with `unique_rowid()` | Sequences |
33
|--------------------------------------|-----------------------------------------|-----------------------------------------------|--------------------------------|
44
| Size | 16 bytes | 8 bytes | 1 to 8 bytes |
55
| Ordering properties | Unordered | Highly time-ordered | Highly time-ordered |

src/current/v25.3/alter-table.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,7 @@ Suppose that you are storing the data for users of your application in a table c
18521852
);
18531853
~~~
18541854
1855-
The primary key of this table is on the `name` column. This is a poor choice, as some users likely have the same name, and all primary keys enforce a `UNIQUE` constraint on row values of the primary key column. Per our [best practices]({% link {{ page.version.version }}/performance-best-practices-overview.md %}#use-functions-to-generate-unique-ids), you should instead use a `UUID` for single-column primary keys, and populate the rows of the table with generated, unique values.
1855+
The primary key of this table is on the `name` column. This is a poor choice, as some users likely have the same name, and all primary keys enforce a `UNIQUE` constraint on row values of the primary key column. Per our [best practices]({% link {{ page.version.version }}/performance-best-practices-overview.md %}#use-functions-to-generate-unique-ids), you should instead use a [`UUID`]({% link {{ page.version.version }}/uuid.md %}) for single-column primary keys, and populate the rows of the table with generated, unique values.
18561856
18571857
You can add a column and change the primary key with a couple of `ALTER TABLE` statements:
18581858

src/current/v25.3/create-sequence.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The `CREATE SEQUENCE` [statement]({% link {{ page.version.version }}/sql-stateme
1111

1212
## Considerations
1313

14-
- Using a sequence is slower than [auto-generating unique IDs with the `gen_random_uuid()`, `uuid_v4()` or `unique_rowid()` built-in functions]({% link {{ page.version.version }}/sql-faqs.md %}#how-do-i-auto-generate-unique-row-ids-in-cockroachdb). Incrementing a sequence requires a write to persistent storage, whereas auto-generating a unique ID does not. Therefore, use auto-generated unique IDs unless an incremental sequence is preferred or required. For more information, see [Unique ID best practices]({% link {{ page.version.version }}/performance-best-practices-overview.md %}#unique-id-best-practices).
14+
- Using a sequence is slower than [auto-generating unique IDs with the `gen_random_uuid()`, `uuid_v4()` or `unique_rowid()` built-in functions]({% link {{ page.version.version }}/sql-faqs.md %}#how-do-i-auto-generate-unique-row-ids-in-cockroachdb) and is likely to cause performance problems due to [hotspots]({% link {{ page.version.version }}/understand-hotspots.md %}). Incrementing a sequence requires a write to persistent storage, whereas auto-generating a unique ID does not. Therefore, use auto-generated unique IDs unless an incremental sequence is preferred or required. For more information, see [Unique ID best practices]({% link {{ page.version.version }}/performance-best-practices-overview.md %}#unique-id-best-practices).
1515
- A column that uses a sequence can have a gap in the sequence values if a transaction advances the sequence and is then rolled back. Sequence updates are committed immediately and aren't rolled back along with their containing transaction. This is done to avoid blocking concurrent transactions that use the same sequence.
1616
- {% include {{page.version.version}}/performance/use-hash-sharded-indexes.md %}
1717
- By default, you cannot create sequences that are [owned by]({% link {{ page.version.version }}/security-reference/authorization.md %}#object-ownership) columns in tables in other databases. You can enable such sequence creation by setting the `sql.cross_db_sequence_owners.enabled` [cluster setting]({% link {{ page.version.version }}/cluster-settings.md %}) to `true`.

src/current/v25.3/hash-sharded-indexes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ You can specify a different `bucket_count` via a storage parameter on a hash-sha
170170

171171
- [Indexes]({% link {{ page.version.version }}/indexes.md %})
172172
- [`CREATE INDEX`]({% link {{ page.version.version }}/create-index.md %})
173+
- [`UUID`]({% link {{ page.version.version }}/uuid.md %})

src/current/v25.3/liquibase.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ Liquibase does not [retry transactions]({% link {{ page.version.version }}/trans
332332
333333
Suppose that you want to change the primary key of the `accounts` table from a simple, incrementing [integer]({% link {{ page.version.version }}/int.md %}) (in this case, `id`) to an auto-generated [UUID]({% link {{ page.version.version }}/uuid.md %}), to follow some [CockroachDB best practices]({% link {{ page.version.version }}/performance-best-practices-overview.md %}#unique-id-best-practices). You can make these changes to the schema by creating and executing an additional changeset:
334334
335-
1. Create a SQL file to add a new UUID-typed column to the table:
335+
1. Create a SQL file to add a new [UUID]({% link {{ page.version.version }}/uuid.md %})-typed column to the table:
336336
337337
{% include_cached copy-clipboard.html %}
338338
~~~ shell

src/current/v25.3/movr-flask-application.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ The `User` class has the following attributes:
110110

111111
- `__tablename__`, which holds the stored name of the table in the database. SQLAlchemy requires this attribute for all classes that map to tables.
112112
- All of the other attributes of the `User` class (`id`, `city`, `first_name`, etc.), stored as `Column` objects. These attributes represent columns of the `users` table. The constructor for each `Column` takes the column data type as its first argument, and then any additional arguments, such as `primary_key`.
113-
- To help define column objects, SQLAlchemy also includes classes for SQL data types and column constraints. For the columns in this table, we use `UUID` and `String` data types.
113+
- To help define column objects, SQLAlchemy also includes classes for SQL data types and column constraints. For the columns in this table, we use [`UUID`]({% link {{ page.version.version }}/uuid.md %}) and `String` data types.
114114
- The `__repr__` function, which defines the string representation of the object.
115115

116116
#### The `Vehicle` class

src/current/v25.3/performance-best-practices-overview.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,7 @@ When a table is created, all columns are stored as a single column family. This
6464

6565
## Unique ID best practices
6666

67-
The best practices for generating unique IDs in a distributed database like CockroachDB are very different than for a legacy single-node database. Traditional approaches for generating unique IDs for legacy single-node databases include:
68-
69-
1. Using the [`SERIAL`]({% link {{ page.version.version }}/serial.md %}) pseudo-type for a column to generate random unique IDs. This can result in a performance bottleneck because IDs generated temporally near each other have similar values and are located physically near each other in a table's storage.
70-
1. Generating monotonically increasing [`INT`]({% link {{ page.version.version }}/int.md %}) IDs by using transactions with roundtrip [`SELECT`]({% link {{ page.version.version }}/select-clause.md %})s, e.g., `INSERT INTO tbl (id, …) VALUES ((SELECT max(id)+1 FROM tbl), …)`. This has a **very high performance cost** since it makes all [`INSERT`]({% link {{ page.version.version }}/insert.md %}) transactions wait for their turn to insert the next ID. You should only do this if your application really does require strict ID ordering. In some cases, using [change data capture (CDC)]({% link {{ page.version.version }}/change-data-capture-overview.md %}) can help avoid the requirement for strict ID ordering. If you can avoid the requirement for strict ID ordering, you can use one of the higher-performance ID strategies outlined in the following sections.
71-
72-
The preceding approaches are likely to create [hotspots](#hotspots) for both reads and writes in CockroachDB. {% include {{page.version.version}}/performance/use-hash-sharded-indexes.md %}
67+
The best practices for generating unique IDs in a distributed database like CockroachDB are very different than for a legacy single-node database.
7368

7469
To create unique and non-sequential IDs, we recommend the following approaches (listed in order from best to worst performance):
7570

@@ -79,6 +74,8 @@ To create unique and non-sequential IDs, we recommend the following approaches (
7974
| 2. [Use functions to generate unique IDs](#use-functions-to-generate-unique-ids) | Good performance; spreads load well; easy choice | May leave some performance on the table; requires other columns to be useful in queries |
8075
| 3. [Use `INSERT` with the `RETURNING` clause](#use-insert-with-the-returning-clause-to-generate-unique-ids) | Easy to query against; familiar design | Slower performance than the other options; higher chance of [transaction contention](#transaction-contention) |
8176

77+
Traditional approaches using monotonically increasing [`INT`]({% link {{ page.version.version }}/int.md %}) or [`SERIAL`]({% link {{ page.version.version }}/serial.md %}) data types will create [hotspots](#hotspots) for both reads and writes in a distributed database like CockroachDB. {% include {{page.version.version}}/performance/use-hash-sharded-indexes.md %}
78+
8279
### Use multi-column primary keys
8380

8481
A well-designed multi-column primary key can yield even better performance than a [UUID primary key](#use-functions-to-generate-unique-ids), but it requires more up-front schema design work. To get the best performance, ensure that any monotonically increasing field is located **after** the first column of the primary key. When done right, such a composite primary key should result in:
@@ -155,7 +152,7 @@ Time: 1ms total (execution 1ms / network 0ms)
155152

156153
Note that the above query also follows the [indexing best practice]({% link {{ page.version.version }}/indexes.md %}#best-practices) of indexing all columns in the `WHERE` clause.
157154

158-
### Use functions to generate unique IDs
155+
### Use functions to automatically generate unique IDs
159156

160157
{% include {{ page.version.version }}/faq/auto-generate-unique-ids.md %}
161158

src/current/v25.3/row-level-security.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ GRANT SELECT, INSERT, UPDATE, DELETE ON invoices TO app_dev;
404404

405405
Each application will need to set the tenant context for the session. In this example, you will use the `application_name` session variable to pass in a tenant ID that will later be extracted from the variable.
406406

407-
Specifically, the UUID following the period in `application_name` is the tenant ID. We will use the `current_setting()` function in our RLS policies to extract the ID.
407+
Specifically, the [UUID]({% link {{ page.version.version }}/uuid.md %}) following the period in `application_name` is the tenant ID. We will use the `current_setting()` function in our RLS policies to extract the ID.
408408

409409
{{site.data.alerts.callout_danger}}
410410
For multi-tenancy to work correctly, this setting **must** be reliably managed by the application layer and passed in the connection string.

src/current/v25.3/schema-design-table.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,9 @@ For detailed reference documentation for each supported constraint, see [the con
288288

289289
To set default values on columns, use the `DEFAULT` constraint. Default values enable you to write queries without the need to specify values for every column.
290290

291-
When combined with [supported SQL functions]({% link {{ page.version.version }}/functions-and-operators.md %}), default values can save resources in your application's persistence layer by offloading computation onto CockroachDB. For example, rather than using an application library to generate unique `UUID` values, you can set a default value to be an automatically-generated `UUID` value with the `gen_random_uuid()` SQL function. Similarly, you could use a default value to populate a `TIMESTAMP` column with the current time of day, using the `now()` function.
291+
When combined with [supported SQL functions]({% link {{ page.version.version }}/functions-and-operators.md %}), default values can save resources in your application's persistence layer by offloading computation onto CockroachDB. For example, rather than using an application library to generate unique [`UUID`]({% link {{ page.version.version }}/uuid.md %}) values, you can set a default value to be an automatically-generated `UUID` value with the `gen_random_uuid()` SQL function. Similarly, you could use a default value to populate a `TIMESTAMP` column with the current time of day, using the `now()` function.
292292

293-
For example, in the `vehicles` table definition in `max_init.sql`, you added a `DEFAULT gen_random_uuid()` clause to the `id` column definition. This set the default value to a generated `UUID` value. Now, add a default value to the `creation_time` column:
293+
For example, in the `vehicles` table definition in `max_init.sql`, you added a `DEFAULT gen_random_uuid()` clause to the `id` column definition. This set the default value to a generated [`UUID`]({% link {{ page.version.version }}/uuid.md %}) value. Now, add a default value to the `creation_time` column:
294294

295295
{% include_cached copy-clipboard.html %}
296296
~~~ sql

0 commit comments

Comments
 (0)