<p>I have a distributed Java application running on 5 application servers. The servers all use the same Oracle 9i database running on a 6th machine.</p>

<p>The application need to prefetch a batch of 100 IDs from a sequence. It's relatively easy to do in a single-threaded, non-distributed environment, you can just issue these queries:</p>

<pre class="lang-sql prettyprint-override"><code>SELECT seq.nextval FROM dual;
ALTER SEQUENCE seq INCREMENT BY 100;
SELECT seq.nextval FROM dual;
</code></pre>

<p>The first select fetches the first sequence ID that the application can use, the second select returns the last one that can be used.</p>

<p>Things get way more interesting in a multithreaded environment. You can't be sure that before the second select another thread doesn't increase the sequence by 100 again. This issue can be solved by synchronizing the access on the Java side - you only let one thread begin fetching the IDs at one time.</p>

<p>The situation becomes really hard when you can't synchronize because parts of the application doesn't run on the same JVM, not even on the same physical machine. I found some references on forums that others have problems with solving this problem too, but none of the answers are really working not to mention being reasonable.</p>

<p>Can the community provide a solution for this problem?</p>

<p>Some more information:</p>

<ul>
<li>I can't really play with the transaction isolation levels. I use JPA and the change would affect the entire application, not only the prefetching queries and that's not acceptable for me.</li>
<li><p>On PostgreSQL I could do the following:
<code>SELECT setval('seq', NEXTVAL('seq') + n - 1)</code></p></li>
<li><p>The solution by Matthew works when you can use a fixed increment value (which is perfectly acceptable in my case). However is there a solution when you don't want to fix the size of the increment, but want to adjust it dynamically?</p></li>
</ul>

[{'answer_id': 43830, 'author': 'Matthew Watson', 'author_id': 3839, 'author_profile': 'https://Stackoverflow.com/users/3839', 'pm_score': 5, 'selected': True, 'text': '<p>Why not just have the sequence as increment by 100 all the time? each "nextval" gives you 100 sequence numbers to work with</p>\n\n<pre><code>SQL&gt; create sequence so_test start with 100 increment by 100 nocache;\n\nSequence created.\n\nSQL&gt; select so_test.nextval - 99 as first_seq, so_test.currval as last_seq from dual;\n\n FIRST_SEQ   LAST_SEQ\n---------- ----------\n         1        100\n\nSQL&gt; /\n\n FIRST_SEQ   LAST_SEQ\n---------- ----------\n       101        200\n\nSQL&gt; /\n\n FIRST_SEQ   LAST_SEQ\n---------- ----------\n       201        300\n\nSQL&gt; \n</code></pre>\n\n<p>A note on your example.. Watch out for DDL.. It will produce an implicit commit</p>\n\n<p><strong>Example of commit produced by DDL</strong></p>\n\n<pre><code>SQL&gt; select * from xx;\n\nno rows selected\n\nSQL&gt; insert into xx values (\'x\');\n\n1 row created.\n\nSQL&gt; alter sequence so_test increment by 100;\n\nSequence altered.\n\nSQL&gt; rollback;\n\nRollback complete.\n\nSQL&gt; select * from xx;\n\nY\n-----\nx\n\nSQL&gt; \n</code></pre>\n'}, {'answer_id': 43991, 'author': 'serg10', 'author_id': 1853, 'author_profile': 'https://Stackoverflow.com/users/1853', 'pm_score': 1, 'selected': False, 'text': "<p>Matthew has the correct approach here.  In my opinion, it is very unusual for an application to reset a sequence's current value after every use.  Much more conventional to set the increment size to whatever you need upfront.</p>\n\n<p>Also, this way is much more performant.  Selecting nextval from a sequence is a highly optimised operation in Oracle, whereas running ddl to alter the sequence is much more expensive.</p>\n\n<p>I guess that doesn't really answer the last point in your edited question...</p>\n"}, {'answer_id': 44457, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 2, 'selected': False, 'text': "<p>Why do you need to fetch the sequence IDs in the first place?  In most cases you would insert into a table and return the ID.</p>\n\n<pre><code>insert into t (my_pk, my_data) values (mysequence.nextval, :the_data)\nreturning my_pk into :the_pk;\n</code></pre>\n\n<p>It sounds like you are trying to pre-optimize the processing.</p>\n\n<p>If you REALLY need to pre-fetch the IDs then just call the sequence 100 times.  The entire point of a sequence is that it manages the numbering.  You're not supposed to assume that you can get 100 consecutive numbers.</p>\n"}, {'answer_id': 45011, 'author': 'Matthew Watson', 'author_id': 3839, 'author_profile': 'https://Stackoverflow.com/users/3839', 'pm_score': 1, 'selected': False, 'text': '<p>For when you don\'t want a fixed size increment, sequences aren\'t really what you are after, all they really guarantee is that you will be getting a unique number always bigger than the last one you got. There is always the possibility that you\'ll end up with gaps, and you can\'t really adjust the increment amount on the fly safely or effectively. </p>\n\n<p>I can\'t really think of any case where I\'ve had to do this kind of thing, but likely the easiest way is just to store the "current" number somewhere and update it as you need it.</p>\n\n<p>Something like this.</p>\n\n<pre><code>drop table t_so_test;\n\ncreate table t_so_test (curr_num number(10));\n\ninsert into t_so_test values (1);\ncreate or replace procedure p_get_next_seq (inc IN NUMBER, v_next_seq OUT NUMBER) As\nBEGIN\n  update t_so_test set curr_num = curr_num + inc RETURNING curr_num into v_next_seq;\nEND;\n/\n\n\nSQL&gt; var p number;\nSQL&gt; execute p_get_next_seq(100,:p);\n\nPL/SQL procedure successfully completed.\n\nSQL&gt; print p;\n\n         P\n----------\n       101\n\nSQL&gt; execute p_get_next_seq(10,:p);     \n\nPL/SQL procedure successfully completed.\n\nSQL&gt; print p;\n\n         P\n----------\n       111\n\nSQL&gt; execute p_get_next_seq(1000,:p);\n\nPL/SQL procedure successfully completed.\n\nSQL&gt; print p;\n\n         P\n----------\n      1111\n\nSQL&gt; \n</code></pre>\n'}]
['https://Stackoverflow.com/questions/43808', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/686/']