HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

Best practices for generating unique multi-column keys for weak entities?

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
uniquemulticolumnweakkeysgeneratingpracticesforentitiesbest

Problem

How should one generate non-unique, non-natural identifiers for weak entities?

For example, if order_id is the primary key for an order table, and (order_id, item_number) is the primary key for an order_item table with a foreign key on order_id, how best to generate item_number?

A few of possibilities come to mind, but none seem ideal:

-
Autoincrement item_number: the order_item entity is no longer weak, and the composite key is redundant.

-
Use a trigger to search for the current max item_number for a given order_id, then increment: if a row is deleted this could lead to reassigning a PK to a different record - that doesn't seem like a good idea? (edit: this can also be done without using triggers as explained in joanolo's answer)

-
Use a trigger to create a new sequence for every order_id, and somehow draw item_numbers from the appropriate sequence: this is functionally the desired behaviour, but seems like it would be a mess to implement. Is it even possible to reference a sequence by an order_id?

Edit - closely related (if not duplicate):

  • Create unique sequence per set of rows sharing the same foreign key value



  • Serial numbers per group of rows for compound key

Solution


  1. is the least error-prone, simplest and fastest.



Trigger solutions like in 2. or 3. are subject to subtle race conditions under concurrent write access.

Make item_number a serial column and also the PK for order_item in this case. Stick with the default values drawn from the underlying sequence and never update the column.

  • Auto increment SQL function



Create a multi-column index on (order_id, item_number) for performance of typical queries. (Might as well be UNIQUE, but does not have to be.) In a typical setup (order_id and item_number can both be plain integer), the multicolumn index happens to be just as small and fast as an index on just order_id:

  • Is a composite index also good for queries on the first field?



(Like I commented:) Typically, the only important role of an item number is to be unique (and immutable). If you need a stable sort order among items, you might just rely on the serial value of item_number. Be aware that those numbers are not necessarily in order of transaction commits. It may be useful to add the transaction timestamp current_timestamp (or possibly statement_timestamp() or clock_timestamp()) to the row. Depends on requirements and access patterns.

You can add a VIEW for the human eye, with item-numbers per order_id starting from 1, dynamically generated with row_number(), ordered by above criteria. But operate with the unique, immutable item_number internally.

  • Create unique sequence per set of rows sharing the same foreign key value

Context

StackExchange Database Administrators Q#161080, answer score: 4

Revisions (0)

No revisions yet.