Skip to Main Content
  • Questions
  • Sequence functionality without a real sequence

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Joachim.

Asked: December 02, 2021 - 7:45 am UTC

Last updated: December 07, 2021 - 5:05 pm UTC

Version: 19

Viewed 1000+ times

You Asked

Dear Tom,

I am looking for a way to create a function or procedure that works like a sequence.
To the background, we use a sequence to create a unique key in our application until the sequence comes to the limit.
Then, we found, that most of the created keys from the sequence are not used (they where only temporarily used and nothing stored with this key).
So we build a table with all the "unused" keys and create a function to get one of these keys each time we need a key.
But now, we are facing massive row lock contentions because of very high frequency to that function and table.
I am really interested to know, if there is a way to create a function or procedure that can cache 1000 entries for all processes.
Do you have any idea to create such functionality or any other idea to fix our locking issue during the access to the table with the keys?

best regards
Joachim

and Chris said...

Why do you want to backfill the missing sequence values? What exactly is the limit you're referring to?

we are facing massive row lock contentions because of very high frequency to that function and table.

Ultimately building your own unique number generator will hit this (or similar) issues. To ensure you assign each number (at most) once, you need to serialize access to the procedure. Which will lead to concurrency issues.

Really the best thing you can do here is increase whatever limit you're hitting. If this is just the sequence maxvalue, increase with:

alter sequence ... maxvalue <new limit>


If it's something else let us know and we'll see what we can do to help.

Do you have any idea to create such functionality or any other idea to fix our locking issue during the access to the table with the keys?

If you're really stuck with the limit (e.g. it's hardcoded into a 3rd party app or similar), you could try using a queue. You can do this in the database with Advanced Queueing.

Just queue up all the missing numbers and call the dequeue process to consume the next value. You'll need to build some process to re-queue any values where the DB process fails/rolls back.

But I repeat: this should be a last resort. Ultimately unless you increase the limit now at some point you'll consume all the missing values and be forced to increase it to use your application!

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Contra rationem

AQ4dummies, December 06, 2021 - 10:12 pm UTC

-- source table
create table holes as select level id from dual connect by level <= 10;
delete holes where id in (2,3,9); -- some ids are missing
commit;

-- lost numbers
create table lostsexuence(
  lsx number primary key
) organization index;

-- recover a lost ids
insert into lostsexuence 
select "."
from (select id+1 a, lead(id) over(order by id)-1 b from holes),
xmltable('xs:int($A) to xs:int($B)' passing a as a, b as b columns "." number)
where a <= b;
commit;

-- seXuence.nextval
create or replace function get_lostsex return  number as
  cursor sxcu is select t.rowid, t.lsx from lostsexuence t for update skip locked;
  ur urowid;
  sx number;
begin
  open sxcu;
  fetch sxcu into ur, sx;
  delete lostsexuence t where t.rowid = get_lostsex.ur;
  close sxcu;
  return sx; -- returns null if the values have run out
end;
/

-- initial content
select listagg(id, ',') within group (order by id ) ids from holes union all
select listagg(lsx,',') within group (order by lsx) ids from lostsexuence;

IDS           
--------------------
1,4,5,6,7,8,10
2,3,9

-- usage
insert into holes values (get_lostsex());
insert into holes values (get_lostsex());
commit;

-- result
select listagg(id, ',') within group (order by id ) ids from holes union all
select listagg(lsx,',') within group (order by lsx) ids from lostsexuence;

IDS               
------------------
1,2,3,4,5,6,7,8,10
9

Chris Saxon
December 07, 2021 - 5:05 pm UTC

Sure you can roll your own - but why not use the functionality provided for you?

More to Explore

Design

New to good database design? Check out Chris Saxon's full fundamentals class.