Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Shailendra.

Asked: November 25, 2004 - 11:41 am UTC

Last updated: January 16, 2013 - 11:54 am UTC

Version: 8.0.0

Viewed 10K+ times! This question is

You Asked

Hi,
It has always been a great learining experiences reading the text on this site. Now i have my own problem and posting my question for the first time. Hope i make some sense.

Can i have same sequence name for 10 different sequences. what do we mean by sequence_owner.

I have a scenario where there are 10 different sequence owners accessing different sequences with different sequence ranges but have same sequence name. These sequences generates a next value for respective unix processes running in unix background. Is there a possibility where a sequence owner 1 can access a sequence owned by sequence owner 2.

The problem i am facing now in my application is that i see a error saying a unique id(generated by individual sequences) already exist in the database.

Thanks you very much and keep up the good work.

and Tom said...

drop 9 of them and replace them with private synonyms.


ops$tkyte@ORA9IR2> @connect a/a
ops$tkyte@ORA9IR2> set termout off
a@ORA9IR2> set termout on
a@ORA9IR2> create sequence seq;

Sequence created.

a@ORA9IR2> select a.seq.nextval from dual;

NEXTVAL
----------
1

a@ORA9IR2> @connect b/b
a@ORA9IR2> set termout off
b@ORA9IR2> set termout on
b@ORA9IR2> create synonym seq for a.seq;

Synonym created.

b@ORA9IR2> select b.seq.nextval from dual;

NEXTVAL
----------
2

b@ORA9IR2>


Rating

  (40 ratings)

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

Comments

RE: Oracle Sequences.

Shailendra., November 25, 2004 - 12:36 pm UTC

Hi,
Thanks for the quick response. However, i cannot drop 9 sequences and create synonyms since all the 10 sequences are supposed to generate seuqence in diffrerent sequence ranges for different Unix background processes. I doubt if they are doing it what they are supposed to do and hope that these values are not clashing.

Tom Kyte
November 25, 2004 - 12:40 pm UTC

i'm not following your logic here? why can't you? you just said you needed something unique.


How about you restate the question from the begining - it seems to me you were have a "duplicate" sequence problem -- this'll solve it.

RE:Oracle Sequences

Shailendra, November 25, 2004 - 12:58 pm UTC

Hi,
Sorry to confuse you. I will restate my question.
I have 10 background process in Unix. Each of which access oracle database to generate unique id using oracle sequences.
These sequences are owned by the respective unix background processes and have the same sequence name.
Each sequence generates unioque id in a seperate range value.

for eg.,

Sequence owner sequence name Min Value Max Value Last Number
------------- ------------- ---------- --------- -----------
cleard10 SEQ_APP 1 100 45
cleard11 SEQ_APP 101 200 110
cleard12 SEQ_APP 201 300 256
cleard13 SEQ_APP 301 400 372
cleard14 SEQ_APP 401 500 487
cleard15 SEQ_APP 501 600 578
cleard16 SEQ_APP 601 700 611
cleard17 SEQ_APP 701 800 718
cleard18 SEQ_APP 801 900 801

Suddenly i have started getting error messages in application log files saying that the generated sequence number already
exist in a database. I doubt if there is some problem with these sequences. My application log does not give me the sequence
owner or the last number retrived.

Can you see any problems here?




Tom Kyte
November 25, 2004 - 3:37 pm UTC

sure -- if you are using "cycle" then 101 would be generated over and over and over.

look -- you have 100 values for each one -- run this often enough and you'll definitely get "dups"

RE:Oracle Sequences

Shailendra., November 26, 2004 - 3:38 am UTC

Hi,
Thanks for the reply, but it really doesn't solve my problem as i have NO CYCLE set for each of the sequences and also once any of the sequence reaches 90% of the usages i get a alert and then i change the sequence range in my example i will start the range for each sequence from 901-1000, 1001-1100, 1101-1200 ....



Tom Kyte
November 26, 2004 - 9:29 am UTC

seems like a lot of work

but if you are getting "duplicates" and what you said above is "true" -- then you are doing the duplication yourself (someone is reusing a sequence).

Not much I can do to fix this -- it would be a problem in the code outside of the database.


I'm still left wondering "why so complex". You need an ID -- a single sequence seems to do the trick. Oh well.

RE:Oracle Sequences.

Shailendra, November 26, 2004 - 9:32 am UTC

Thanks for all your help.
Keep up the good work. Its really nice to have a site as yours

amit, May 24, 2007 - 12:48 am UTC

In our project we need to generate SequenceID for each and every record we insert.
Currently we are using Oracle Sequence to get SequenceID, but this is becoming bottleneck as this takes more than 90% of time taken to process data.
Any other proven approaches, suggestions we will be greatly appreciated to generate unique SequenceID across sessions. (Even after restarting Application server need to have last SequenceID used.)
Tom Kyte
May 26, 2007 - 10:42 am UTC

show us the code?

I doubt seriously it is 90% in sequences.... they are highly concurrent and pretty darn efficient.

You can make them more efficient by

alter sequence S cache 100000;

for example - that'll reduce the recursive sql and commit that happens otherwise every 20 sequence gets.

Associating sequences with primary key of a table

Dheeraj, September 02, 2007 - 12:58 am UTC

Hi Tom,

I have a requirement where-in I am initially inserting some rows in a table by hard-coding primary
key (with digits -> 1,2,3...) and at a later point of time, I want to use a sequence that
automatically detects the max value of primary key column and generates max(PK) + 1 as the next
column value.
All in all, can I associate a sequence with primary key of a table, such that whenever this
sequence is used to populate primary key, it detects the max value of that column and generates max
+ 1.

Test case:

create table test
(id number constraint test_pk primary key);

insert into test
values(1);

insert into test
values(2);

insert into test
values(3);

select * from test;

ID
----------
1
2
3

Now, my requirement is to use a sequence such that it is associated with test_pk And whenever I use
this sequence to populate test table, it detects the max value of the ID column and generates, MAX
+ 1, 4 in above example.

I don't want to create a sequence that has *start with* clause as MAX(id) + 1, of test table.

Hope I am able to explain my issue.

Many thanks,

Dheeraj

Tom Kyte
September 05, 2007 - 12:41 pm UTC

I addressed this exact cut and pasted question elsewhere, look there please.

RAC and sequences,

A reader, September 07, 2007 - 4:49 pm UTC

In a multi-instance database, the sequences can be cached in any or all of the instances and when sequence.nextval is selected we can get the sequence from whichever instance we have connected. This can result in sequence to be in improperly sequenced.

How to generate a sequence number in a sequential manner in RAC database? I was once told that we can achieve this by setting "cache=1" while creating a sequence. But this approach can cause performance issues.

Any other way?

Thanks,

Tom Kyte
September 12, 2007 - 10:19 am UTC

a sequence is simply a surrogate key generator, you cannot get them "out of order", if their value is taken by you to actually MEAN something, you have missed the point of them.


do NOT do cache=1 (that won't actually fixed it, each instance still caches...)

If you need some sort of artificial ordering, you mean to timestamp your records, do not use a sequence to presume any sort of "order"

Followup to the question on RAC and sequences

Kim Berg Hansen, September 13, 2007 - 3:25 am UTC

Hi, Tom

Concerning the ordering of sequences in a RAC environment:

Documentation for the CREATE SEQUENCE statements says about the ORDER clause:

ORDER Specify ORDER to guarantee that sequence numbers are generated in order of request. This clause is useful if you are using the sequence numbers as timestamps. Guaranteeing order is usually not important for sequences used to generate primary keys.

ORDER is necessary only to guarantee ordered generation if you are using Oracle Database with Real Application Clusters. If you are using exclusive mode, sequence numbers are always generated in order.


Just curious: Won't that ORDER clause affect performance if all nodes in the RAC has to keep each other up-to-date on next value of the sequence?

But if there is a task definitely requiring order, wouldn't this still be a better approach than for example serializing on a single record in some "pseudo-sequence" table?

Thank you in advance for your thoughts :-)

Regards

Kim Berg Hansen

Tom Kyte
September 15, 2007 - 7:18 pm UTC

this would be setting

SLOW=true /* very true, most true, absolutely true, slower than slow */

do not even go there, I won't even talk about that option.

sequences and RAC

A reader, September 17, 2007 - 12:33 pm UTC

The developers have used "order by id" where the values of ID is generated by Oracle sequences.

In RAC, there are chances that the new record may not have the largest sequence number and the ORDER BY clause fails to retrieve the correct order.

The problem is not with the sequnces and RAC, it is convincing the team that "this is the way the sequences work". But I can understand their problem that they cannot go back and change their code (and even design).

But at the end, the problem remains as a problem(in RAC).

Thanks,

Tom Kyte
September 18, 2007 - 3:35 pm UTC

your developers have a bug therefore, have them fix it.

I cannot understand why they cannot fix a bug?


the problem remains as a problem in single instance oracle too.

time...          session 1                   session 2
--------         --------------              -----------------
0                grab seq=100
1                                            grab seq=101
2                                            commit
3                commit


which one is the last set of data input into the system? and what would your sequence say about that.


If you really truly want to defeat the purpose of databases - serialize this, but expect it to be as slow as you can imagine.

sequences and code checking,

A reader, September 25, 2007 - 12:59 pm UTC

Our application is in the process of migrating to 10g RAC environment from single instance 9i database.

We need to find out any attributes that are populated by Oracle sequences in the database and are part of business logic within a query.

For example, if emp_id is populated using the sequences and if a SQL query has "select max(emp_id)" or "select...order by emp_id", or something similar that may result in incorrect results due to the behavior of sequences in RAC, how to find out those SQL statements in the database?

The database has bunch of schemas and each schema has tons of stored procedures/packages. I want to avoid human effort as much as possible to find out the impacted sql statements.

The thought I have given so far is, store all the SQL statements that run in the database by executing statement through crontab. The statement collects SQL statements from v$sql.

But still this process is tedious. Is there a better way to achive this?

Thanks,

Prob in seq

Asheesh, January 06, 2009 - 11:46 pm UTC

Hi Tom,
In our Database(Oracle8i Enterprise Edition Release 8.1.7.4.0 - Production), we have a sequence which generates primary key values used in many tables. The max limit set for this sequence is 99999999. Now slowly its reaching its limit. For this we have increased the size of our table cols, procs, triggers and functions to NUMBER(9) from NUMBER(8). Now when we are inserting values it gives error:

ORA-00604... Recursive SQL ; ORA-01401....Inserted too large.

Why this error is coming as we have already increased the size in column tables , all procedures,tiggers and functions?

Please guide
Tom Kyte
January 07, 2009 - 9:20 am UTC

it is coming because somewhere you DID NOT do this.

find the statement that is failing - that would be useful to your debugging efforts.

sequences in RAC

Victor, February 11, 2009 - 4:48 pm UTC

Is it possible to cache sequence numbers on Only one instance of RAC. We have a two-node RAC on RDBMS 9.2.0.7.0.

Thanks.
Tom Kyte
February 12, 2009 - 10:50 am UTC

sure, just access the sequence on one of the nodes....

but I'm not sure what the general purpose use of this would be (to set the cache amount by instance)

what is the goal, what is the reasoning, what are you trying to accomplish with this?

given that sequences are never gap free
given that sequences never can really be used to order information by "age" accurately

in RAC or not.

sequences

Victor, February 13, 2009 - 12:17 pm UTC

Follow up to my above request:

In our two node RAC, as we cache sequences, inserts to table is not getting sequence numbers in a monotonically increasing manner.
Example:
sequence object with CACHE 5:
Instance 1: sequence numbers 10-14 cached
Instance 2: sequence numbers 15-19 cached
Assuming,
Session A connects to Instance 2: inserts first record in table t1 that gets sequnce number 15
after a few seconds Session B connects to Instance 1: inserts second record in the same table t1 that gets a sequnce number 10.

Our application expects the second record in table t1 should have sequence number that is greater than the first record in table t1. that is not the case in the above scenario. Looks likes, to resolve this, i was thinking NOT caching the sequnce in either instance. However, will it have significant performance impact by not caching sequences?

Will pinning the sequence object in the shared pool by using KEEP procedure minimize performance overhead of not caching?

Thanks as always for your time.


Tom Kyte
February 16, 2009 - 11:40 am UTC

... In our two node RAC, as we cache sequences, inserts to table is not getting
sequence numbers in a monotonically increasing manner. ...

that is ok, they never will - anyone that relies on a sequence as if it were "a sortable timestamp" is not going to be 'happy'


single instance:

process 1 gets nextval
process 2 gets nextval
process 2 commits
process 1 commits

Ok, what is "first" there?? I say process 2 is definitely first, absolutely and definitely first.



You will have to either

a) NOCACHE everywhere and live with the performance issues

b) fix the bug in the developed code that does not work correctly on a single instance machine, let alone RAC.



No, pinning will do NOTHING - if you use the sequence, it'll be 'pinned' already in real life.


What CACHE does is avoid the recursive transaction to update seq$ - if you cache 10, then we 'update seq$; commit' only ever 10 nextval calls. If you nocache you will observe:

a) many more log file sync waits, each nextval call will wait for that
b) many more cross instance transfers, you have the very definition of a hot block now.



So how do I determine the creation order

Gosta Hulden, December 17, 2009 - 7:35 am UTC

Hi Tom. We have a business requirement that says that it should be possible to get the last created record and that it must be possible to determine the creation order. We have 4 RAC nodes (oracle 10g) and the timestamp on those nodes can differ a bit.

You have rejected many solutions, but can you suggest a solution? Using a Sequence with order is supposedly slow. Using a table for id's is according to you "Yuk!" And the timestamps are not reliable. So a suggested solution that can scale would be highly appreciated.
Tom Kyte
December 17, 2009 - 10:22 am UTC

Ask the business

what is the definition of the last created record, what does that mean to you?


They will tell you what they mean.

And then your job is to explain to them exactly, precisely and without using big terms what that means.


And then my suggested solution to them would be "WHY do you BELIEVE you need this?"


A sequence with order is not only slow, it is precisely as reliable as a timestamp.



Business requirements are not mandatory, I wish people would get that fact. They are in fact requests, that you have to take to this 'business' and explain the cost. You will find they actually change their minds if you talk to them reasonably sometimes.

And - it is your job, you are not a coder, not a dba, you are a liaison between this "business" (I hate that term, it is like a nebulous, amorphous group of something) and the application.

David aldridge, December 18, 2009 - 10:14 am UTC

You might try suggesting to the business that if there is nothing in the data itself that defines what the creation order is then you might as well return the rows in a completely random order, because they would never be able to test the requirement anyway. That might prompt them to make a better defined request ;)

use NTP

Mike Kutz, December 21, 2009 - 5:02 pm UTC

Gosta,
Timestamps not accurate? huh? what?
Your sys-admin must not be doing his/her job.
The solution to synchronizing times across computers has been around since the dawn of the internet. (pre-1985)

All of my linux servers have "exact time" to within 100ms of NIST. I'm sure it is higher then that. I just don't have anyway to accurately test it.

However, it seems that if you are on Windows OS, you are S.O.L.
Reading the wiki page on "Network Time Protocol" points you to a Microsoft KB article (939322) that seems to state "Windows can not maintain time with <1s accuracy using the Time Service".

(back on track)
As Tom mentioned - "you are a liaison between this 'business' and the application."
(this is so true.)

This is where you really start asking the tough questions of "why?".
WHY do you need FIFO of the records? (first in, first out)
WHY are timestamps not accurate on the RAC nodes?
WHY can't you use something else besides timestamps to ensure FIFO?
(this next one is from my experience in using sequences)
WHY can you not live with 'holes' in the database?
ie seq.nextval followed by a ROLLBACK


Tom Kyte
December 23, 2009 - 6:58 am UTC

Mike -

what Gosta is referring to is the fact that timestamps - even if perfectly synchronized with NTP - are not the answer to "what is the last record"

The timestamp is assigned to a record when it is inserted. A record does not exist however until it is committed. A record that 'came to exist' after some other record - might have a timestamp that is older.

Here is the best analogy I can think:

A timestamp is like the time of conception.
The age of a completed committed transaction is its birthdate.

When you ask of a pair of people "who is newest (youngest) person between you two" - we go by birthdate, not their timestamp of conception :)

This is why timestamps, sequences, anything that does not physically SERIALIZE all modifications to the table(s) are unreliable for telling you "what is the newest" or "what is the oldest".


time                  session1                   session2
t0                    insert sysdate
t1                                               insert sysdate
t2                                               commit
t3 (5 minutes later)  commit


session2 has the 'newest' transaction, session1 never got to have that status, but I claim that session1 has the newest transaction and should have that status until another session comes and claims it.



But it does get you right back to the last set of questions - Mr. Business dude, define "last" and tell us "why".


latest operations in parallel systems

Carsten, December 28, 2009 - 4:57 am UTC

Actually it is way more obvious than your example Tom that the definition of "latest" is somewhat flawed nowadays.

They have RAC, which means at least 2 Computers processing data at the same time. How would you define latest by business means when the last 2 operations happened at the same time at each of the 2 nodes ?
Assuming multi-core servers this fits even to none RAC systems and you save yourself discussions about job interruptions, scheduling and the like.

As Tom suggested they will usually either drop that requirement and say: ok give me a list of all records of the last X seconds or they will state that either of the 2 is fine.
I would even expect that you could easily stress the definition "at the same time" to human standards, which means any of the latest records within several seconds. Although you might not be able to set cache to millions, you can now calculate a reasonable cache setting.

Sequences in RAC with NOORDER: Not Unique?

Manjunath, January 11, 2010 - 12:55 am UTC

Hi Tom,
In one of our projects(10.2.0.4, 2 node RAC) , we have the client DBA team that helps us extensively on all the dba activities. Recently, while checking some performance issues, a developer noticed that the sequences are created with nocache(or cache with a low number), and 'order' and had approached me for suggestions if we can modify them to improve performance. The dba team has checked with Oracle support on the need for 'order', it appears that Oracle has come out saying that if 'noorder' is used then duplicate numbers could be generated for the same sequence from different instances. Is this right? I was under the impression that Oracle always generates unique numbers, rac or otherwise. 'order' is used in rac only to ensure that values from different instances are generated that adhere(follow) to timestamp.
Also, in context to sequences what does collision mean? Can you please clarify?

Thanks and regards
Manjunath
Tom Kyte
January 18, 2010 - 6:11 am UTC

that is wrong, please post your SR# and if what you say is true, I'll educate them.

More likely, you have misunderstood what was said, in any case, I'll clarify


noorder just means that that if you select s.nextval from dual; on each NODE in the cluster one after the other - they will not necessarily be INCREASING- node 1 might return 100, node 2 might return 10, node 3 might return 1000, and so on. They won't be ordered.


how to achieve this

A reader, January 11, 2010 - 4:29 pm UTC

drop table dept;

create table dept
(dept_id NUMBER(2,0),
Location VARCHAR2(50) ,
CONSTRAINT PK_DEPT_ID PRIMARY KEY (DEPT_ID)
);

drop sequence dept_val;

create sequence dept_val

insert into dept ( dept_id, location ) values (dept_val.nextval, 'London');

insert into dept ( dept_id, location ) values ( dept_val.nextval, 'New York' );

insert into dept ( dept_id, location ) values (dept_val.nextval, 'Singapore' );

insert into dept ( dept_id, location ) values (dept_val.nextval,'Tokyo' );

commit;

alter table dept
add tz_dept timestamp;

update dept set Tz_dept =
(select localtimestamp from dual);


select * from dept;

drop table employee;

create table employee
( emp_id number(2,0),
dept_id number ( 2,0 ),
salary number ( 9,2),
tier_id number ( 2,0 ),
CONSTRAINT PK_EMP PRIMARY KEY (EMP_id),
CONSTRAINT FK_DEPTid FOREIGN KEY (DEPT_id)
REFERENCES DEPT (DEPT_id ) enable ,
CONSTRAINT FK_tier FOREIGN KEY (tier_id)
REFERENCES tier (tier_id ) ENABLE
)

drop sequence emp_val;

CREATE SEQUENCE EMP_VAL;

delete from employee;

insert into employee (emp_id, dept_id, salary, tier_id) values ( emp_val.nextval , 2 , 20000, 4);

insert into employee (emp_id, dept_id, salary, tier_id) values (emp_val.nextval , 4, 200000, 1);

insert into employee (emp_id, dept_id, salary, tier_id) values (emp_val.nextval , 3, 25000, 4);

insert into employee (emp_id, dept_id, salary, tier_id) values (emp_val.nextval , 1 , 60000 , 2);

insert into employee (emp_id, dept_id, salary, tier_id) values (emp_val.nextval , 1 , 30000 , 3);

alter table employee
add tz_emp timestamp;

update employee set Tz_emp =
(select localtimestamp from dual);

select * from employee

commit;

drop table tier;

create table tier
( tier_id number ( 2,0 ),
tier_name varchar2(30)
)

alter table tier add constraint pk primary key(tier_id);

drop sequence tier_val

create sequence tier_val

insert into tier (tier_id, tier_name) values (tier_val.nextval,'Director' );

insert into tier (tier_id, tier_name) values (tier_val.nextval,'Manager' );

insert into tier (tier_id, tier_name) values (tier_val.nextval,'Analyst' );

insert into tier (tier_id, tier_name) values (tier_val.nextval,'Intern' );

commit;

alter table tier
add tz_tier timestamp;

update tier set Tz_tier =
(select localtimestamp from dual);

select * from tier

2. Write the PL/SQL to create two stored procedures in a package. The first procedure will take in an department ID and will return both the current timestamp and a list of the different distinct tiers belonging to that department ID. These will be returned as two separate parameters.

The second stored procedure will take in a tier ID and provide back the second highest salary for that tier.







Tom Kyte
January 18, 2010 - 12:17 pm UTC

homework? Not since 1987 do I do homework.

Sequences in RAC with NOORDER: Not Unique?

Allie, January 18, 2010 - 8:40 am UTC

Tom,
This is related to the comment posted by Manjunath from India. I have detailed below the SR I opened with Oracle Support about this problem with the sequences. The SR was to confim a document that I found in metalink a year ago, where the same thing was detailed in it, that the use of NOORDER could cause a risk of duplicated sequence numbers in different instances in the RAC.
After I got the first confirmation from Oracle support, I even re-posted the question in the SR to make sure that their answer was clear and that I was not misundersting them.

The service request with Oracle Support is "SR #3-1281002431: Sequence configuration for RAC"

Any clarification will be appreciated so that I can submit your comments to Oracle support related to this SR.

Thanks,
Allie
Tom Kyte
January 18, 2010 - 5:43 pm UTC

that is not the format of an SR number...


they loo like this

3452123.123

SR number formats have changed since Metalink was migrated to a new version..

A reader, January 18, 2010 - 8:41 pm UTC


Cheers.

Sequences in RAC with NOORDER: Not Unique?

Allie, January 19, 2010 - 8:36 am UTC

Tom,
Sorry but this is the only Request Id that I can find in the SR, and the number is 3-1281002431. Since metalink was migrated to the new version, they changed the format. I reviewed the entired header of the SR and there is no other number that is related to the SR id.
Anyway I can email to you a copy of the SR if you want me to, just let me know which email address you want me to send it and I will.
Thanks,
Allie
Tom Kyte
January 19, 2010 - 4:54 pm UTC

thomas.kyte@oracle.com

I cannot see that tar, they added a layer of security with the new release...

Help

RA, January 30, 2010 - 12:11 am UTC

Hi Tom,

I understand sequences are the preferred way to generate sequential numbers in Oralce. But how can I use them for generating limited sequential numbers for things like line item sequencial numbers? For example, I have a "order_line_items" table that has "order_id" and "seq_no" columns (for each order_id there will be line items starting with 1). The requirement is that when a new order item is added, it should use the next sequential item number for that order_id. I can't think of an easy way to do this in my pl/sql procedure. Currently what I have coded in my procedure is:

insert into order_line_items (order_id, seq_no, ....)
values (p_order_id, (select max(seq_no)+1 from order_line_items where order_line_items where order_id=p_order_id), ....);

Since all inserts to this table will be through this procedure, there should be no surprises in a multi-user system. But there must be a better, scalable way to do this - I can't figure out any though. Can you please help?

TIA,
RA


Tom Kyte
February 01, 2010 - 9:36 am UTC

... I understand sequences are the preferred way to generate sequential numbers ...

no, sequences are a way to generate unique numbers, please don't think they are sequential (not assured) or anything like that, just think of them as UNIQUE - that is all. You'll never be sorry if you think of them as unique, you'll be sorry if you think of them as sequential.
... The requirement is that
when a new order item is added, ...

change the requirement, the requirement is - to be blunt - stupid, I've heard it a thousands times - it is a silly, non-requirement.

Revisit the requirment - anything such as a timestamp or a sequence (in non-rac environments!) would suffice. You just care about the ordering of information, you do not care if they go 1, 2, 3, 4, 5.... the application MIGHT, but then have row_number() for that! You do not need, want nor desire a truly sequential number.

The only way to get one will

a) involve SERIALIZATION (as in ONE PERSON AT A TIME)
b) lots of work

all for nothing, nothing useful.



convince me there is a technical merit to this 'requirement'.


I'll have to point out now that a huge part of a developers job is to point out when requirements are nonsensical and hugely expensive. If you do not, you are not doing your job. We know what can be done technically and the cost of doing so - the 'business' (whatever the heck that is) does not. They might have a desire (we'd like to see numbers 1,2,3,4,... on a report or on a screen) which can be met thousands of different ways - in this case, this would be a reporting function, not a data attribute value.

A reader, February 02, 2010 - 9:22 pm UTC

okay, okay, I know where you stand on sequence gaps - they are inevitable like death and taxes, I understand (been a reader of asktom for 7+ years)..

However, IN THIS PARTICULAR CASE, if all the inserts are allowed only through a pl/sql procedure that has an insert coded like:

insert into order_line_items (order_id, seq_no, ....)
values (p_order_id, (select max(seq_no)+1 from order_line_items where order_line_items where
order_id=p_order_id), ....);

how can it cause serialization (as in one person at a time)? The scalar subquery with select max is done within the insert statement itself, so it cannot cause a serialization - nobody is selecting and waiting for further processing or whatever before an insert. And unless two people can execute the procedure at the same exact time, with the same exact order_id (highly, highly unlikely because our application design will not allow that) it will not create serialization / nor gaps. Can you please explain if you think otherwise?

I actually wanted to find out how you would implement this using sequences. Let us say, I am ok with gaps in the sequence numbers, but how do I implement it (because the line_item sequences will be reused for the next order_id). Do you suggest resetting the sequence each time and start with 1 for each order_id? I dont see how it can be done (would appreciate if you could show a demo). I understand we can use a sequence if it was a synthetic key, but for natural keys like order_id+line_item_seq how do you implement using oracle sequence? Anybody who has done this (in the database as against from the app) could you share your experience too?

Tom Kyte
February 03, 2010 - 10:00 am UTC

... how can it cause serialization (as in one person at a time)? ...

You have to figure out how to cause the serialization - YOU MUST serialize however. Else, you cannot uniquely assign your numbers (think about this, think about what the logic would look like with two users concurrently inserting into the same order).


The point is that is it NOT that serialization would automagically occur, but you had BETTER INTRODUCE SOME serialization if you want the right answer.


... I actually wanted to find out how you would implement this using sequences....

I would not, I don't purposely do things the wrong way. Not for hypothetical reasons, not in real life.

Use a sequence, period, it is right, it makes you look smart, it is safe, it works, it is a good practice, it makes you more efficient - anything else - just put "NOT" after each comma in that list and that would describe the situation.


... Anybody who has done this (in the database as against from the app) could you
share your experience too?
....

I'll make fun of them. Your max(seq_no)+1 is a "newbie mistake that is made every time by people that do not think about concurrency". It doesn't work with more than one user.


remember reads do not block writes.
Writes do not block reads.
Multiversioning - read consistency.

and most of all CONCURRENT ACCESS.....


A reader, February 03, 2010 - 3:11 pm UTC

Tom,

I am afraid you do not understand what I am asking. Sorry, I get a feeling that you are more inclined to lecture than answering my questions.

Let me state my problem again (instead of you having to page up and read again) - I have a table (order_line_item) with a composite primary key order_id+order_line_item_seq. All DML is through pl/sql procedures. The pl/sql procedure will accept order_id as an "in" variable and need to generate the order_line_item_seq starting with 1 for each item in the order. I cannot figure out how to use oracle sequence here - because the sequence will need to be reset for each new order_id (and how will we know if its a new order_id unless we query the database to find it?) I do not see a natural way to use an oracle sequece here. So, I coded my insert as:

insert into order_line_items (order_id, seq_no, ....)
values (p_order_id, (select max(seq_no)+1 from order_line_items where order_id=p_order_id), ....);


You still haven't explained how this can cause a serialization. Please note all inserts go through the pl/sql procedure only (you see, I follow your principles!).

Again, these are the questions I hope you will answer:

1)How can the above insert cause a serialization when all inserts are done through the pl/sql procedure (two people can never call the procedure with the same order_id at the same time - that is taken care of in the application) ? When the select max()+1 is done within the insert statement how can it cause a serialization? I don't see any scope for serialization, and there will be no gaps in the line_item_sequence - please show me I am wrong.

2)Can you demonstrate how to do this using oracle sequences (that is, without having to query the db to see if the order_id is new and then resetting the sequence to 1).

I agree the max()+1 is not an elegant solution, but can you show me a better way using oracle sequences?

If you do not understood my question, please let me know. Thanks for your time.
Tom Kyte
February 04, 2010 - 12:03 pm UTC

I tried to tell you that:

... insert into order_line_items (order_id, seq_no, ....)
values (p_order_id, (select max(seq_no)+1 from order_line_items where
order_id=p_order_id), ....);

...

WILL NOT CAUSE SERIALIZATION.

I wrote:

The point is that is it NOT that serialization would automagically occur, but you had BETTER INTRODUCE SOME serialization if you want the right answer.

Using emphasis not to lecture but to try to make sure the point was clear.

Please ask yourself what will happen if two people do that simultaneously????? Think about it - if two people, at the same time, issue

(select max(seq_no)+1 from order_line_items where
order_id=p_order_id)

and p_order_id is the same value, what happens?

They both get the *same* value.



If you have a unique constraint on the table (order_id,seq) - then in fact this will cause seriallization - on the unique constraint. When the first transaction commits - the second will FAIL (*fail*, rollback the insert, lose, not work). If you don't have a constraint, you will create duplicates.

And what happens when someone else deletes from order and resequences when you are inserting? Have you thought about that? Please - on a white board (now I am lecturing, absolutely) put a line down the middle of the board and on the left hand side write "session 1" and on the right - "session 2". Then start playing with ordering of operations hitting your table simultaneously and ask yourself "what happens when"



1) hahahahah, I'm going to lecture again.....

(two people can never call the procedure with the
same order_id at the same time - that is taken care of in the application) ?


either you are wrong (that is won't) or let us say you are right....

THEN, what I wrote above applies 1,000% - read what I wrote (that you just chastised me for writing...)

I wrote:


The point is that is it NOT that serialization would automagically occur, but you had BETTER INTRODUCE SOME serialization if you want the right answer.



You just wrote to me that you in fact claim to be introducing some..... drum roll..... serialization:

that is taken care of in the application

so, what was harsh or confusing about what I wrote??? you seem to agree with me that serialization would be necessary!!! I don't get it?


As for the application ensuring this, hahahahaha - I laugh. You talk as if there is and will be one application (there won't, your application will go the way of dinosaurs tomorrow and something else will come in to muck it all up). Your application will do this HOW? Please tell us.


So, bottom line, you agree that you must serialize on the order line item table at the level of orders. You agree that you want to do this sequencing using the MOST EXPENSIVE way possible (hey, lets run a query! extra work! for nothing! well - to ensure we limit concurrency artificially anyway, there is that!)


2) no, because that would be silly. they don't work that way - and they DO NOT have to work that way. Your 1,2,3,4,5... concept is something a report writer would do for an end users convenience. Go this route (of doing gap free starting with 1) and you'll be writing resequencing code for when a line item is deleted - or how about moved up or down (might not be a requirement today - but it WILL BE some day, trust me) - or duplicated or whatever.



Just use s.nextval and be done with it. When you query:

select order.*, order_line.*, 
       ROW_NUMBER() over (order by seq_populated_by_seq_nextval) PRETTY_SEQ
  from order, order_line
 where order.order# = order_line.order#
 order by order_line.seq_populated_by_seq_nextval;


or, more generically:

select order.*, order_line.*, 
       ROW_NUMBER() over (partition by order_line.order# order by seq_populated_by_seq_nextval) PRETTY_SEQ
  from order, order_line
 where order.order# = order_line.order#
 order by order_line.order#, order_line.seq_populated_by_seq_nextval;


and you have what you want.



I understood your question 100%

I answered it 100% (I told you YOU have to enforce serialization or have duplicates using your max()+1 'trick', you just told us "we are enforcing serialization" - if you include a unique constraint - we'll enforce it too - but cause a failure of the second and nth concurrent transactions for the same order.


I hope this clears it up.


Guaranteed

JerryQ, February 03, 2010 - 3:54 pm UTC

Hi "A Reader"

I look after a fairly high-load RAC and sequences cause a lot of performance issues. Generally I try to force the developers to avoid them, and if thats not possible, to use cached sequences - where numbers can get lost if nodes are re-started. Numbers will also get lost if a transaction has to be rolled back.
There are times however when there is a specific business requirement to guarantee sequential, ordered numbers. For these, we use our own "sequence" table, and use of these will force any other transaction that needs that sequence to wait until the transaction is committed. This is obviously a major performance hit, and so should be used sparingly.
In your case, the only way I know of to guarantee the sequential order-line numbers is to have some form of gateway before doing your insert - e.g.

select order_id into piOrderId from order where orderid = X for update;
insert into order_line_items(...(select max(..)+1)..)

This will cause any other process thats attempting to add a line item for the same order to wait until your process is committed.

Its not great, and should only be used if there is a real business requirement.

There is also the issue of a developer bypassing your procedure - this can be avoided by putting the "select for update" into a trigger on the order_line table.

Hope this helps.

Cache

JerryQ, February 03, 2010 - 4:00 pm UTC

Hi "A Reader"

Should have said that due to performance issues with sequences in RAC, we use large caches plus noorder. If sequence is "order"ed, nodes have to communicate with each other every time they hand out a sequence number, and the caching is pretty much pointless.

RA, February 03, 2010 - 4:34 pm UTC

Sorry Tom if I sounded disrespectful in my above post. I realized I was not able to frame my question to you properly. As they say 'Engineers language is drawing' I guess Oracle technologists language is sql and pl/sql - so let me try to demo to you what I am asking using sql:


SQL> ed
Wrote file afiedt.buf

  1  create table order_line_items
  2  (order_id varchar2(20) not null,
  3  line_item_seq number(3) not null,
  4  item_id varchar2(20) not null,
  5* quantity number (9,2))
SQL> /

Table created.


-I want to use a procedure to insert records into the table. All inserts go through the procedure. The line_item_seq has to increment starting with 1 for each order_id. I want to use oracle sequences, but I figured out this probably is a better way:

SQL> create or replace
  2  procedure p_add_oline_item(p_order_id in varchar2, p_item_id in varchar2, p_quantity number)
  3  as
  4  begin
  5  insert into order_line_items (order_id, line_item_seq, item_id, quantity)
  6  values (p_order_id, (select max(line_item_seq)+1 from order_line_items where order_id=p_order_id), p_item_id, p_quantity);
  7  commit;
  8  end;
  9  /

Procedure created.

--This is what it would look like using a sequence (as I know of). It is psedo code - oracle does not have an easy way to reset a sequence. I think this is enough to give you the idea -

  1* create sequence oline_item_seq start with 1 increment by 1 maxvalue 999
SQL> /

Sequence created.

SQL> create or replace
  2  procedure p_add_oline_item2(p_order_id in varchar2, p_item_id in varchar2, p_quantity number)
  3  as
  4  begin
  5  if not exists (select null from order_line_items where order_id=p_oder_id) then
  6  alter sequence oline_item_seq.nextval reset;
  7  end if;
  8  insert into order_line_items (order_id, line_item_seq, item_id, quantity)
  9  values (p_order_id, (select max(line_item_seq)+1 from order_line_items where order_id=p_order_id), p_item_id, p_quantity);
 10  commit;
 11  end;
 12  /

Warning: Procedure created with compilation errors.


This is a very common design and we can easily do from java. I want to do it in the db using pl/sql. I was intending to use sequences until I started coding when I realized it is not as easy as I thought it was. I want to know if there is a better way to do this using oracle sequences - can you demo please, I am eager to learn. Else, do you think this is a special case where select max()+1 is better than a sequence?

Tom Kyte
February 04, 2010 - 12:14 pm UTC

select max() - more resources than seq.nextval.


select max() - requires you serialize at the level of an order, if you do not (using select for update on the order table by order# for example), you will block on the unique constraint that MUST be in place on the (order#,line#) columns. The blocked session will FAIL when the blocker commits - failures = bad when they can easily and obviously be avoided.



You would not reset the sequence. You just want to be able to "order the data", if you are in RAC (as above commenter was writing about), you would probably just use a SYSTIMESTAMP for ordering (first come, first serve - ties - we don't care about). So, you would always populate line_item_number with seq.nextval and if you wanted to order by "date of insertion", you would use systimestamp. In most cases seq.nextval would be sufficient.



... This is a very common design and we can easily do from java....

only by nailing the database with extra work, and by writing extra code to serialize.

Or, you could do less work in the database and write less code by using a sequence.


Your Choice.

RA, February 03, 2010 - 4:39 pm UTC

Oops, the procedure using the sequence that I meant to post was:

SQL> create or replace procedure p_add_oline_item2(p_order_id in varchar2(20), p_item_id in varchar2(20), p_item_id number(9,2))
  2  )
  3  as
  4  l_oder_id varchar2(20);
  5  begin
  6  if not exists (select null from order_line_items where order_id=p_oder_id) then
  7  exception when no_data_found then
  8  alter sequence oline_item_seq.nextval reset;
  9  end if;
 10  insert into order_line_items (order_id, line_item_seq, item_id, quantity)
 11  values (p_order_id, oline_item_seq.nextval, p_item_id, p_quantity);
 12  commit;
 13  end;
 14  /

Warning: Procedure created with compilation errors.


RA from Sterling, VA

SeánMacGC, February 05, 2010 - 6:02 am UTC

I don't know you DBMS version, but if it's not 11g then what you're trying there will fail.

Try something like:

SQL> create or replace procedure p_add_oline_item2(p_order_id in varchar2(20), p_item_id in varchar2(20), p_item_id number(9,2))
  )
  as
  l_oder_id varchar2(20);
 begin
    insert into order_line_items (order_id, line_item_seq, item_id, quantity)
    select p_order_id, oline_item_seq.nextval, p_item_id, p_quantity from dual;
  exception 
    when dup_val_on_index
      then NULL;

END;
/

Sequences in RAC with NOORDER: Not Unique?

saurabh, February 18, 2010 - 4:28 am UTC

Tom,

Did you receive the email from Allie (from UT,USA) regarding the oracle SR, which purportedly says that NOORDER could cause a risk of duplicated sequence numbers in different instances in the RAC. If you have received that email, can you please clarify further.

Thanks,
Saurabh
Tom Kyte
February 18, 2010 - 9:43 am UTC

I did and I wrote to the support analyst correcting their misconceptions.


oracle

nagabhushanam, May 01, 2010 - 11:21 am UTC

hi in this site is very useful for me

squences

nagabhushanam, May 01, 2010 - 11:44 am UTC

hi sir i want to limitations of sequences
Tom Kyte
May 06, 2010 - 11:09 am UTC

other than the maximum value is 9,999,999,999,999,999,999,999,999,999, I'm not sure what you would be looking for

Guaranteeing Unique Sequences in RAC

Ian Mills, May 26, 2010 - 5:23 am UTC

Tom,

I'm keen to understand exactly how Oracle guarantees uniqueness for a NOORDER sequence in a RAC environment. This subject is mentioned several times above. I'd like to understand how this works.

Time Node Seq
1 1 10
2 2 12
3 1 11
4 2 13
5 1 ??

In the above scenario I can understand that the ordering of the sequence values is out of step as the sequence is cached seperately on each node. This is not a problem if the sequence is only used to generate unique key values. However, how does Oracle ensure that it doesn't return a sequence value of 12 on node 1. To do this it must be know that node 2 has previously used this sequence value. If this is the case then there must be communication betwen the nodes every time we retrieve a sequence value?

Thanks
Ian
Tom Kyte
May 26, 2010 - 8:06 am UTC

the sequences work off of a table seq$

in seq$ there is data about the current value and the cache size.

when a node needs to get a new sequence value and they are currently "empty" of values - they will

a) lock and read out the current value from seq$, call this X
b) increment it by the cache size in seq$
c) commit

They now can generate values X, X+1, X+2, ... X+cache_size-1 without overlaps - since anyone else would get an X value from seq$ that was X+cache_size and they would generate numbers starting at X+cache_size

Thanks

A reader, May 26, 2010 - 8:14 am UTC

Perfect explanation. Thanks for clarifying.

using sequence

A reader, October 07, 2010 - 11:57 am UTC

Hi Tom
Thanks for your time.

I have an equirement

I want to use the numbers 15,000,000 to 17,000,000 ( in a step of 1 ) in my program( code)

ways to do it

a)
create table t1 ( x number); -- to store these numbers

..pseudo code

for x in 15000000 .. 17000000
loop
insert into t1 values(i);
end loop;
commit;
end;
/


then.. want to insert these numbers into another table t2 in my code as follows ( in batches of 100000 )

table t2 is
(x number, y varchar2(100) )


cursor c1
select * from ( select * from t1 order by 1 ) where rownum<=100000;
begin
...
bulk insert into t2(x) values ( from cursor..);
... other stuffs
end;

b)
using oracle sequences ( start ..15000000 max 17000000 caching the sequences.. 100000 at a time and doing bulk

insert into t2.?
how to do it?

c) any other method

thanks a lot.

Tom Kyte
October 11, 2010 - 10:46 am UTC

no version :(


answer is "none of the above" - just directly insert into T2.

Using this technique to create lots of data
http://blog.tanelpoder.com/2008/06/08/generating-lots-of-rows-using-connect-by-safely/

ops$tkyte%ORA11GR2> create table t ( x number );

Table created.

Elapsed: 00:00:00.01
ops$tkyte%ORA11GR2> 
ops$tkyte%ORA11GR2> 
ops$tkyte%ORA11GR2> insert /*+ append */ into t
  2  with data as
  3  (select level l from dual connect by level <= 1000)
  4  select 15000000+rownum-1
  5    from data, data, (select * from data where rownum<=2)
  6  /

2000000 rows created.

Elapsed: 00:00:03.17

Sequences in RAC environment

Manuel Vidigal, February 23, 2011 - 9:34 am UTC

Hi Tom,

Regarding your answer to this question
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:29059659958024#2324274100346850298

The solution you presented with the query:

select order.*, order_line.*,
ROW_NUMBER() over (partition by order_line.order# order by seq_populated_by_seq_nextval)
PRETTY_SEQ
from order, order_line
where order.order# = order_line.order#
order by order_line.order#, order_line.seq_populated_by_seq_nextval;

will not work 100% in RAC environments, since you you can have seq_populated_by_seq_nextval with lower values for the last orders.

Am I right?

I think the only workaround here is to use SYSTIMESTAMP (knowing that there is a really really low chance of having duplicate timestamps), or is there any best practice here?

Thanks in advance.
Tom Kyte
February 24, 2011 - 12:26 pm UTC

sequences do not indicate order of anything, never have, never will and people that "count on them to do so" are setting themselves up for a shock.

sequences are simply unique numbers - treat them as such. they have gaps, they do not represent "time" or "order". They are just unique numbers.

they were just asking to have line items numbered from 1 to N, there wasn't anything necessarily about them having a specific order, I just chose (had to chose something) to order by a sequence. I could have as easily ordered by the string 'x' (but then it would not be deterministic and I don't like that). I know the sequence populated column will be unique making the assignment of row_number deterministic (repeatable)

Sequence Number starting with 2 and not 1 initially

Balaji, January 09, 2013 - 11:03 pm UTC

Hi Tom,

The site is very useful, i am refering to the site most of the times.

I have a problem, for which i don't find cause/solution.

My problem is,

1. I create a table

create table TEST_TABLE
(
NUMBER_CHECK number
);

2. I create a sequence number with option start with 1

CREATE SEQUENCE TEST_SEQ MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOORDER NOCYCLE ;

3. I Insert a row using sequence nextval into the table created

INSERT INTO TEST_TABLE VALUES (TEST_SEQ.NEXTVAL);

4. When i query the table, the value is 2 and not starting with 1, why?

NUMBER_CHECK
------------
2

5. Then i rollback insert DML and now no records present in the table and create one more sequence with the same option

CREATE SEQUENCE TEST_SEQ_2 MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOORDER NOCYCLE ;

6. Now, I Insert use the second create sequence nextval into the table

INSERT INTO TEST_TABLE VALUES (TEST_SEQ_2.NEXTVAL);

7. When i query the table, the value is 1, which is correct, why initially sequence number starting with 2 ?

NUMBER_CHECK
------------
1

Please help me in identifing cause and solution for this problem.
Tom Kyte
January 14, 2013 - 1:08 pm UTC

it is a side effect of deferred segment creation that was resolved in a later patch set.

if you use the "segment creation immediate" clause - you will not observe this behavior in your unpatched relesase.

You should assume nothing about sequences however. It would be perfectly legitimate and acceptable for this to happen:

create table
create sequence
insert into table seq.nextval
select * from table

NUMBER_CHECK
-------------
         42



the only think you can rely on is the fact that the seq.nextval value will be unique and hence can be used as a primary key.

Is this true for a RAC

Al Ricafort, January 14, 2013 - 7:41 pm UTC

Hi Tom,

Is below statement true for an Oracle RAC if you cache your sequence?

"the only think you can rely on is the fact that the seq.nextval value will be unique and hence can be used as a primary key. "


Tom Kyte
January 15, 2013 - 10:28 am UTC

yes, a sequence only promises to return a unique value that can be used as a surrogate - regardless of environment.

it does not promise to be gap free
it does not promise to return them in any order (except at a painfully high cost that I refuse to even think about discussing)

Is this true for a RAC

Al Ricafort, January 16, 2013 - 12:52 am UTC

Hi Tom,

I was trying to figure out how instances ensure that sequence is unique especially if it is cached. At first I was thinking if they directly communicate with each other but it seems that it is not necessary. It appears that the last_number in the all_sequences is all that is needed.

So for example if I define a sequence like this in a RAC with 2 instances:

CREATE SEQUENCE test_seq
START WITH 1
INCREMENT BY 1
CACHE 20
NOCYCLE;

The 1st instance to issue 'select test_seq.nextval' will have a range from 1 to 20. This instance will then update the last_number to 21. The 2nd instance, when it issues 'nextval', will then see that the last_number is 21 so it will have a range from 21 and 40 and update the last_number to 41. When the 1st instance has reached 20 it will then continue from 41 to 60 and so on.

Is this basically how it is done?



Tom Kyte
January 16, 2013 - 11:54 am UTC

exactly.