# Generating sortable unique ID(primary key) across the cluster in an entity-relationship model

**URL:** <https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789>\
**Category:** Using FoundationDB\
**Created:** [February 8, 2023, 2:53pm UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789 "2023-02-08T14:53:26Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Apache](https://avatars.discourse-cdn.com/v4/letter/a/2acd7d/32.png) [@Apache](https://forums.foundationdb.org/u/Apache)\
**Post date:** [February 8, 2023, 2:53pm UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789/1 "2023-02-08T14:53:26Z")

</div>

I am very new to FDB, and trying to understand what is the recommended strategy to generate sortable IDs across the cluster.

Say, for example, I want to create an entity-relationship model on top of FDB. For each entity I would like to assign a sortable unique ID(primary key) across a cluster. What is the idiomatic way of generating this ID for FDB? Or does FDB provide a way to request a sortable unique ID from the cluster that can be used as a primary key of an entity?

---

<div class="post-metadata">

**Author:** ![markus.pilman](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/markus.pilman/32/379_2.png) [@markus.pilman](https://forums.foundationdb.org/u/markus.pilman)\
**Post date:** [February 8, 2023, 2:59pm UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789/2 "2023-02-08T14:59:55Z")

</div>

It depends what you need… If you need something unique that preserves insert ordering you can use a version stamp. You could also use an atomic op to just have a counter, but that might generate a hot key which is non-optimal. Read-modify-write is also possible, but due to concurrency control it will limit your throughput and is only a good option for low-throughput workloads. So in most cases I would say using a version stamp is the best option.

---

<div class="post-metadata">

**Author:** ![Apache](https://avatars.discourse-cdn.com/v4/letter/a/2acd7d/32.png) [@Apache](https://forums.foundationdb.org/u/Apache)\
**Post date:** [February 8, 2023, 3:27pm UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789/3 "2023-02-08T15:27:21Z")

</div>

Thank you for the reply.

Please could you point me to an example on how to use version stamp for primary key?

---

<div class="post-metadata">

**Author:** ![markus.pilman](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/markus.pilman/32/379_2.png) [@markus.pilman](https://forums.foundationdb.org/u/markus.pilman)\
**Post date:** [February 8, 2023, 5:03pm UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789/4 "2023-02-08T17:03:41Z")

</div>

You can do that with an [atomic operation](https://apple.github.io/foundationdb/api-python.html#atomic-operations) (look for ` Transaction.set_versionstamped_key(key, param)` in the documentation),

---

<div class="post-metadata">

**Author:** ![rajivr](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/rajivr/32/1100_2.png) [@rajivr](https://forums.foundationdb.org/u/rajivr)\
**Post date:** [February 9, 2023, 3:56am UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789/5 "2023-02-09T03:56:56Z")

</div>

> [@Apache](#):
>
> Say, for example, I want to create an entity-relationship model on top of FDB. For each entity I would like to assign a sortable unique ID(primary key) across a cluster

> [@markus.pilman](#):
>
> If you need something unique that preserves insert ordering you can use a version stamp.

From what I understand, when using versionstamp, we need to be careful if our transaction block is non-idempotent. Quoting from [this](https://apple.github.io/foundationdb/developer-guide.html#transactions-with-unknown-results) link,

> Avoid generating IDs within the retry loop. Instead, create them prior to the loop and pass them in. For example, if your transaction records an account deposit with a deposit ID, generate the deposit ID outside of the loop.

So, when creating a primary key for the entity that contains a versionstamp, I think you will need to factor in the possibility that you could have two primary keys referring to the same entity, if the transaction retried when the entity was created.

---

<div class="post-metadata">

**Author:** ![Imperatorx](https://avatars.discourse-cdn.com/v4/letter/i/d2c977/32.png) [@Imperatorx](https://forums.foundationdb.org/u/Imperatorx)\
**Post date:** [February 9, 2023, 8:58pm UTC](https://forums.foundationdb.org/t/generating-sortable-unique-id-primary-key-across-the-cluster-in-an-entity-relationship-model/3789/6 "2023-02-09T20:58:44Z")

</div>

I would just use an id generator that is independent of commit versions, like [GitHub - f4b6a3/tsid-creator: A Java library for generating Time-Sorted Unique Identifiers (TSID).](https://github.com/f4b6a3/tsid-creator) or Twitter’s snowflake algorithm, which are sorted by creation time. If you do not use auto-generated ids, it is easier to write tests too.
