Sequences are the springboards that enable PostgreSQL databases to vault beyond mundane, monotonous data – automatically generating unique identifiers to give wings to everything from primary keys to version numbers and more.

But raw sequence power alone isn‘t enough when complex business needs arise. Their potentials must be mastered across on-premise, multi-region toplogies.

That mastery journey starts with understanding the pivotal setval function – able reset sequence trajectories mid-flight with surgical precision.

In this comprehensive guide, we’ll uncover all there is know about harnessing sequences via setval, including:

  • Common setval use cases with examples
  • Performance optimization considerations
  • Sequence locking and contention caveats
  • Obscuring sequence values strategies
  • Multi-region distribution factors
  • Sequential data type pairings

And more. Along the way, we’ll crystallize the optimal approaches to mastering PostgreSQL sequences using setval.

A Primer on PostgreSQL Sequences

For those newer to PostgreSQL, sequences are special database objects that generate sequential numbers defined by a few key parameters:

Start – Beginning value

Increment – Step increase amount

Minvalue/Maxvalue – Lower and upper boundaries

Once created, sequences can be called via handy functions that automatically supply the next number in sequence:

  • nextval – Increment and return sequences next number

  • currval – Return current value most recently generated

For example:

CREATE SEQUENCE user_id_seq START 101 INCREMENT BY 1; 

SELECT nextval(‘user_id_seq‘); -- Returns 101
SELECT nextval(‘user_id_seq‘); -- Returns 102

SELECT currval(‘user_id_seq‘); -- Returns 102  

This automated numbering makes sequences extremely useful for:

  • Primary keys – Unique row identifiers like id columns

  • Transaction IDs – Ordering operations that happened over time

  • Version numbers – Tracking iteration order of data changes

And various other uses where monotonically incrementing values come in handy.

However, business needs evolve. And developers often need to manually intervenesequence trajectory midstream with surgical precision.

That‘s where the setval function enters the scene – with the power to rewrite the course sequenced values take by:

  • Resetting sequences to restart counting

  • Resuming values after new data loaded

  • Handling gaps gracefully

  • Accelerating bulk inserts through caching

And more. Let‘s explore some common examples.

Restarting Numbering Sequences

A basic but incredibly useful application of setval is restarting the counting on an existing sequence. Rather than needing to drop and recreate sequences to start from scratch.

For example, say we generate monthly customer order IDs that we want to reset each new year back to 1:

CREATE SEQUENCE order_id_seq START 1; 

-- Code inserts order_ids starting at 1 

-- ...year end, prepare for next...

SELECT setval(‘order_id_seq‘, 1); -- Reset to 1!

setval rewinds the sequence counter back to the starting value so numbering can start fresh. This avoids recreating sequences constantly.

Benefits include:

  • Consistent data types remain intact unlike drops

  • Permissions preserved

  • Parameters stay unchanged (increment, min/max)

Making setval restart far simpler than dropping/recreating sequences when requirements pivot.

Restarting Parallel Sequences

In distributed topologies, developers often leverage not just one but multiple sequences in parallel across shard clusters or regions.

Restarting requires coordinating resets across sequences consistently to avoid mismatched values.

For example, say we shard customer data across regions using id sequences:

Region A

nextval: cust_id_seq_a -> 501 
currval: cust_id_seq_a -> 500

Region B

nextval: cust_id_seq_b -> 1001
currval: cust_id_seq_b -> 1000 

Resetting requires care to realign:

Reset Parallel Sequences

SELECT setval(‘cust_id_seq_a‘, 1, false); 

SELECT setval(‘cust_id_seq_b‘, 501, false);

This avoids cust_id collisions by bumping the second sequence to continue values right after the first. Keeping key continuity across the distributed topology.

Handling Gaps Gracefully

Gaps in sequences occasionally happen when records get inserted and deleted later non-sequentially.

For example, records 1-10 created. But record 5 gets removed:

Sequence Values

1, 2, 3, 4, 6, 7, 8 ,9 10 

Rather than just resetting values back to 1, setval can smoothly resume right after the gap:

SELECT setval(‘id_sequence, 6);  

This avoids reusing primary keys IDs that already existed. And provides graceful handles when gaps emerge.

Sequence gap visualization

Care is still required to avoid violations from parallel sequence gaps misaligning across distributed databases.

Accelerating Bulk Inserts

Sequences also unlock optimizations for bulk data loads inserting thousands of records in batches.

Typically, each inserted row would trigger a separate nextval sequence call to retrieve the next ID. Causing performance lag:

Bulk Inserts without Sequence Optimization

Unoptimized bulk insert sequence

By instead caching sequence values in larger blocks during data imports using PostgreSQL‘s cache parameter, trips to the sequence object are minimized:

Cached Sequence Bulk Insert

Optimized cached sequence bulk insert

Then setval can pick up counting right where the batch left off:

-- Imported 10,000 records

SELECT setval(‘id_sequence‘, 10000); 

This sequence value caching strategy during bulk inserts avoids thousands of superfluous sequence hits.Accelerating performance dramatically.

Surfacing Sequences Reveals Intensity

One subtle drawback of sequences is they surface intensity of record generation over time directly in the incrementing IDs.

Exposing trends publicly often considered private business intelligence like:

  • User signup rates allowing extrapolation of totals

  • Transaction densities indicating revenue cycles

  • Activity frequency for exploiting vulnerabilities

For example, a sequence starting at 1 and currently sitting at 50,000 reveals avg signup rates.

Strategies like obscuring sequences through hashing mitigate this:

NEXTVAL(MD5(sequence_name));

Salted hashing hinders guessing raw values sequence values shielding trends from unintended eyes.

Weighing Setval vs Application Logic

While powerful, is setval the right tool for a given sequence reset task vs custom app logic?

For example, restarting annual sequences can be achieved either via:

setval

SELECT setval(‘order_id_seq‘, 1); 

Application Logic

if month == 1: 
   run_sql("ALTER SEQUENCE order_id_seq RESTART WITH 1")

Considerations per approach:

setval Application Logic
Scope Database App layer
Separations Centralized Scattered across code
Flexibility Constrained by SQL capabilities Endless options via programming
Performance Optimized Additional network trips
Locking Potential contention Application layer controls timing

In general, setval simplifies restarts avoiding custom code. But some edge cases may justify application logic handling more nuanced needs SQL can’t satisfy.

Sequence Lock Contention Risks

One key caveat of setval is it acquires exclusive locks on sequence objects while running. Blocking other operations targeting the same sequence.

For high volume sequences under constant barrage, setval interventions risk brutal blocking cascades.

Visualizing a Brutal Setval Locking Cascade

sequence lock contention

Strategies to mitigate lock contention risks include:

  • Tune CACHE parameter – Reduce frequency of hitting sequences
  • Batch sequence ops – Consolidate resets into batches
  • Lookahead preallocation – Cache ahead values avoiding locks
  • Parallel sequences – Shard sequence ranges across multiple objects
  • Queue resets offline – Schedule setval during maintenance windows

Carefully assessing risks of sequence contention and planning ahead helps smooth setval integrations.

Multi-Region Sequence Considerations

In globally distributed PostgreSQL deployments, sequences enable uniquely identifying records across logical databases scattered geographically.

Strategies like id sharding prevent collisions:

Region A

  • Sequence A – 1 to 1,000,000
  • Setval offsets to ensure no gaps between regions

Region B

  • Sequence B – 1,000,001 to 2,000,000

This works smoothly until restarts are needed. Resetting sequences requires planning to realign continuity across all regions concurrently:

Multi-Region Sequence Resets

multiregion sequence resets

Without coordination, gaps emerge rapidly causing primary key disasters. Setval equips admins to orchestrate controlled resets globally.

Sequences Breadth – Numeric vs UUID vs Custom

While the most common use case, numbered sequences are just one data type that can be sequenced in PostgreSQL.

Sequences can produce more than incrementing numbers, but also:

  • UUIDs – For obscuring record ids
  • Mappings – Custom data type transformations
  • Geometry – Generate coordinate series
  • Timescales – Sequential timestamps

For example, a UUID sequence:

CREATE SEQUENCE uid_seq AS uuid;

SELECT nextval(‘uid_seq‘);
-- 8aea0f1b-8827-4d58-9bb8-d8bc505c7f59 

SELECT nextval(‘uid_seq‘);
-- 60373941-1650-4c64-8a32-f421e7bc49dc

This opens sequences to alternative data types beyond numeric, like hashes and geospatial values.

PostgreSQL sequences serve up the automatic numbering that powers everything from primary keys to version history.

And setval provides precise control to surgically reshape sequence trajectory on demand through graceful restarts, bulk optimizations, gap handling, and more.

By mastering sequences broadly alongside setval specifically, developers wield annotations that liberate data from the mundane…positioning PostgreSQL to play a transformative role in building bold applications brimming with potential.

The only limit is your imagination.

Similar Posts