Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-04 Thread Vincent de Phily
On Sunday 03 July 2011 07:47:01 Chris Travers wrote:
 On Sun, Jul 3, 2011 at 7:25 AM, Ireneusz Pluta ipl...@wp.pl wrote:
  You may use dense_rank() (or even rank()) window function to map your
  sequence-with-gaps to a no-gap-id which will be used for exports.
 
 The typical case where gapless numbering comes up is something like this:
 
 In Greece, you go get invoice paper from the tax office which is
 numbered in sequence and the government gets a list of the invoice
 forms you have purchased.  You then print the invoices on those paper
 forms, and must number the invoices sequentially and without gaps.  In
 the case of an audit, all paper forms obtained must be accounted for
 as must all gaps in numbering.  You MUST be able to connect each
 sequential invoice number (internally generated) to each invoice form
 (numbered at the tax office).
 
 In this case you really have no choice but to lock some records,
 generate a new gapless id, and save/print it.  Naturally this causes
 the sorts of problems mentioned.

So the problem with Ireneuz's solution is that the mapping isn't stable 
enough. Then how about creating this mapping on disk whenever an export is 
done (assuming exports are much less frequent than inserts) ?

* create table idmap(realid integer references realdata(id), gaplessid
  integer);
* insert into realdata with the usual sequence
* whenever an export of new data is requested :
  * lock table idmap
  * select * from realdata where id  (select max(realid) from idmap) and
 realdata.timestamp  now() -
 'safety_margin_for_inserts_likely_to_rollback'::interval order by id for
 update;
  * insert into idmap
  * unlock table idmap
  * select gaplessid,data from idmap left join realdata


Depending on your insert/export ratio this might be more efficient. And of 
course you can't delete rows 6 months later, but you knew that :p

-- 
Vincent de Phily
Mobile Devices
+33 (0) 142 119 325
+353 (0) 85 710 6320 

Warning
This message (and any associated files) is intended only for the use of its
intended recipient and may contain information that is confidential, subject
to copyright or constitutes a trade secret. If you are not the intended
recipient you are hereby notified that any dissemination, copying or
distribution of this message, or files associated with this message, is
strictly prohibited. If you have received this message in error, please
notify us immediately by replying to the message and deleting it from your
computer. Any views or opinions presented are solely those of the author
vincent.deph...@mobile-devices.fr and do not necessarily represent those of 
the
company. Although the company has taken reasonable precautions to ensure no
viruses are present in this email, the company cannot accept responsibility
for any loss or damage arising from the use of this email or attachments.

-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Vincent Veyron
Le vendredi 01 juillet 2011 à 12:28 +0400, Dmitriy Igrishin a écrit :


 Then I don't clearly understand the existence of locks (the LOCK
 command, SELECT FOR UPDATE clause and so on) if the usage
 of them gives only problems...
 

Chris already explained why twice :

you MUST lock on insert to get gapless sequences

Can't you just :
-create the records with a regular sequence, that will have gaps
-when you want to export, number an additional column from 1 to 10 000
and use that as key
?
-- 
Vincent Veyron
http://marica.fr/
Logiciel de gestion des sinistres et des contentieux pour le service juridique


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Dmitriy Igrishin
Hey Vincent,

2011/7/3 Vincent Veyron vv.li...@wanadoo.fr

 Le vendredi 01 juillet 2011 à 12:28 +0400, Dmitriy Igrishin a écrit :


  Then I don't clearly understand the existence of locks (the LOCK
  command, SELECT FOR UPDATE clause and so on) if the usage
  of them gives only problems...
 

 Chris already explained why twice :

 you MUST lock on insert to get gapless sequences

Not me :-). The OP must do it. So, what problem here? Deadlocks?
Again, if deadlocks are so dangerous, why the LOCK command exists?


 Can't you just :
 -create the records with a regular sequence, that will have gaps
 -when you want to export, number an additional column from 1 to 10 000
 and use that as key
 ?

I don't use any locks explicitly :-)

 --
 Vincent Veyron
 http://marica.fr/
 Logiciel de gestion des sinistres et des contentieux pour le service
 juridique




-- 
// Dmitriy.


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Ireneusz Pluta

W dniu 2011-06-30 20:20, Dmitry Koterov pisze:
And I need as compact uniq_id generation (with minimum holes) as it possible - this is a VERY 
important requirement (to export these values into external systems which accepts only IDs limited 
from 1 to 10).


So I cannot use sequences: sequence value is obviously not rolled back, so if I insert 
nextval(...) as uniq_id, I will have large holes (because of often transaction rollbacks) and 
exhaust 10 uniq_ids very fast. How to deal with all this without sequences?


You may use dense_rank() (or even rank()) window function to map your sequence-with-gaps to a 
no-gap-id which will be used for exports.


Consider this:

test=# select uniq_id_with_gaps, dense_rank() over (order by uniq_id_with_gaps) as 
uniq_id_without_gaps from (select generate_series(1, 100, 7) as uniq_id_with_gaps) a;

 uniq_id_with_gaps | uniq_id_without_gaps
---+--
 1 |1
 8 |2
15 |3
22 |4
29 |5
36 |6
43 |7
50 |8
57 |9
64 |   10
71 |   11
78 |   12
85 |   13
92 |   14
99 |   15

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Chris Travers
On Sun, Jul 3, 2011 at 7:25 AM, Ireneusz Pluta ipl...@wp.pl wrote:

 You may use dense_rank() (or even rank()) window function to map your
 sequence-with-gaps to a no-gap-id which will be used for exports.


The typical case where gapless numbering comes up is something like this:

In Greece, you go get invoice paper from the tax office which is
numbered in sequence and the government gets a list of the invoice
forms you have purchased.  You then print the invoices on those paper
forms, and must number the invoices sequentially and without gaps.  In
the case of an audit, all paper forms obtained must be accounted for
as must all gaps in numbering.  You MUST be able to connect each
sequential invoice number (internally generated) to each invoice form
(numbered at the tax office).

In this case you really have no choice but to lock some records,
generate a new gapless id, and save/print it.  Naturally this causes
the sorts of problems mentioned.

Best Wishes,
Chris Travers

-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Vincent Veyron
Le dimanche 03 juillet 2011 à 18:10 +0400, Dmitriy Igrishin a écrit :

 
 Not me :-). The OP must do it. 

Duh! sorry about that. Indeed, I confused you with Dmitry. 

-- 
Vincent Veyron
http://marica.fr/
Logiciel de gestion des sinistres et des contentieux pour le service juridique


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Alban Hertroys
On 3 Jul 2011, at 16:10, Dmitriy Igrishin wrote:

 you MUST lock on insert to get gapless sequences
 Not me :-). The OP must do it. So, what problem here? Deadlocks?
 Again, if deadlocks are so dangerous, why the LOCK command exists?

It's not deadlocks, it's concurrent updates that are the trouble. If you don't 
lock, you run the risk for two records being assigned the same number 
concurrently.

With a unique constraint added into the mix (and there should be one) that 
means that one of the transactions will fail the unique constraint check on 
commit.

It's possible to catch that in the client and redo the transaction with a new 
ID, but if that's not acceptable (for example because it matters which 
transaction got the ID first) then you need to lock records.

Alban Hertroys

--
If you can't see the forest for the trees,
cut the trees and you'll see there is no forest.


!DSPAM:737,4e109f6e12092079216178!



-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-03 Thread Dmitriy Igrishin
Hey Alban,

2011/7/3 Alban Hertroys dal...@solfertje.student.utwente.nl

 On 3 Jul 2011, at 16:10, Dmitriy Igrishin wrote:

  you MUST lock on insert to get gapless sequences
  Not me :-). The OP must do it. So, what problem here? Deadlocks?
  Again, if deadlocks are so dangerous, why the LOCK command exists?

 It's not deadlocks, it's concurrent updates that are the trouble. If you
 don't lock, you run the risk for two records being assigned the same number
 concurrently.

Thanks for clarify, but I know why resources must be locked when
they are used concurrently :-). See my previous post about SELECT FOR UPDATE
...
and I don't see the problem with it. As well as with the LOCK command.


 With a unique constraint added into the mix (and there should be one) that
 means that one of the transactions will fail the unique constraint check on
 commit.

 It's possible to catch that in the client and redo the transaction with a
 new ID, but if that's not acceptable (for example because it matters which
 transaction got the ID first) then you need to lock records.

Sure.


 Alban Hertroys

 --
 If you can't see the forest for the trees,
 cut the trees and you'll see there is no forest.


 !DSPAM:1257,4e109f6512095013212184!





-- 
// Dmitriy.


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-01 Thread Dmitriy Igrishin
Hey Chris,

The suggestion of using for
 update is a good one, but it doesn't entirely get rid of the problem,
 which is inherent in ensuring gapless numbering in a system with
 concurrent transactions.

Why not?

I mean the following solution:

CREATE TABLE myseq(tabnm text not null, lastid integer not null);

INSERT INTO myseq SELECT 'mytab', 0; -- initialization

CREATE OR REPLACE FUNCTION public.myseq_nextval(a_tabnm text)
 RETURNS integer
 LANGUAGE sql
 STRICT
AS $function$
UPDATE myseq SET lastid = li + 1 FROM
  (SELECT lastid li FROM myseq WHERE tabnm = $1 FOR UPDATE) foo
  RETURNING lastid;
$function$

-- Test

dmitigr= BEGIN;
BEGIN
dmitigr= SELECT myseq_nextval('mytab');
 myseq_nextval
---
 1
(1 row)

dmitigr= ROLLBACK;
ROLLBACK
dmitigr= SELECT * FROM myseq;
 tabnm | lastid
---+
 mytab |  0
(1 row)

So, with this approach you'll get a lock only on INSERT.

dmitigr= CREATE TABLE mytab(id integer not null DEFAULT
myseq_nextval('mytab'));
CREATE TABLE
dmitigr= INSERT INTO mytab DEFAULT VALUES;
INSERT 0 1
dmitigr= INSERT INTO mytab DEFAULT VALUES;
INSERT 0 1
dmitigr= SELECT * FROM mytab;
 id

  1
  2
(2 rows)


-- 
// Dmitriy.


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-01 Thread Chris Travers
On Fri, Jul 1, 2011 at 1:16 AM, Dmitriy Igrishin dmit...@gmail.com wrote:
 Hey Chris,

 The suggestion of using for
 update is a good one, but it doesn't entirely get rid of the problem,
 which is inherent in ensuring gapless numbering in a system with
 concurrent transactions.

 Why not?

Just because it locks less doesn't mean that it doesn't lock.

The point is:  if gaps are acceptable then the sequences which exist
outside of transactions are idea.  If gaps are not acceptable, you
have to lock and force transactions through the system serially which
means a possibility of deadlocks and performance issues.  These issues
are inherent in gapless numbering because you can't get a gapless
sequence when things roll back without such locks.

 I mean the following solution:

 CREATE TABLE myseq(tabnm text not null, lastid integer not null);

 INSERT INTO myseq SELECT 'mytab', 0; -- initialization

 CREATE OR REPLACE FUNCTION public.myseq_nextval(a_tabnm text)
  RETURNS integer
  LANGUAGE sql
  STRICT
 AS $function$
 UPDATE myseq SET lastid = li + 1 FROM
   (SELECT lastid li FROM myseq WHERE tabnm = $1 FOR UPDATE) foo
   RETURNING lastid;
 $function$

 -- Test

 dmitigr= BEGIN;
 BEGIN
 dmitigr= SELECT myseq_nextval('mytab');
  myseq_nextval
 ---
  1
 (1 row)

 dmitigr= ROLLBACK;
 ROLLBACK
 dmitigr= SELECT * FROM myseq;
  tabnm | lastid
 ---+
  mytab |  0
 (1 row)

 So, with this approach you'll get a lock only on INSERT.

True.  But the point us that you MUST lock on insert to get gapless
sequences, and this creates inherent problems in terms of performance
and concurrency, so that you should not use it unless you really have
no other choice (i.e. because the tax authorities demand it).

Best Wishes,
Chris Travers

-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-01 Thread Dmitriy Igrishin
2011/7/1 Chris Travers chris.trav...@gmail.com

 On Fri, Jul 1, 2011 at 1:16 AM, Dmitriy Igrishin dmit...@gmail.com
 wrote:
  Hey Chris,
 
  The suggestion of using for
  update is a good one, but it doesn't entirely get rid of the problem,
  which is inherent in ensuring gapless numbering in a system with
  concurrent transactions.
 
  Why not?

 Just because it locks less doesn't mean that it doesn't lock.

 The point is:  if gaps are acceptable then the sequences which exist
 outside of transactions are idea.  If gaps are not acceptable, you
 have to lock and force transactions through the system serially which
 means a possibility of deadlocks and performance issues.  These issues
 are inherent in gapless numbering because you can't get a gapless
 sequence when things roll back without such locks.

Then I don't clearly understand the existence of locks (the LOCK
command, SELECT FOR UPDATE clause and so on) if the usage
of them gives only problems...


  I mean the following solution:
 
  CREATE TABLE myseq(tabnm text not null, lastid integer not null);
 
  INSERT INTO myseq SELECT 'mytab', 0; -- initialization
 
  CREATE OR REPLACE FUNCTION public.myseq_nextval(a_tabnm text)
   RETURNS integer
   LANGUAGE sql
   STRICT
  AS $function$
  UPDATE myseq SET lastid = li + 1 FROM
(SELECT lastid li FROM myseq WHERE tabnm = $1 FOR UPDATE) foo
RETURNING lastid;
  $function$
 
  -- Test
 
  dmitigr= BEGIN;
  BEGIN
  dmitigr= SELECT myseq_nextval('mytab');
   myseq_nextval
  ---
   1
  (1 row)
 
  dmitigr= ROLLBACK;
  ROLLBACK
  dmitigr= SELECT * FROM myseq;
   tabnm | lastid
  ---+
   mytab |  0
  (1 row)
 
  So, with this approach you'll get a lock only on INSERT.

 True.  But the point us that you MUST lock on insert to get gapless
 sequences, and this creates inherent problems in terms of performance
 and concurrency, so that you should not use it unless you really have
 no other choice (i.e. because the tax authorities demand it).

Sure, but, again, why LOCK and SELECT FOR UPDATE exists ?


 Best Wishes,
 Chris Travers




-- 
// Dmitriy.


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-07-01 Thread Craig Ringer

On 1/07/2011 4:21 PM, Chris Travers wrote:


means a possibility of deadlocks and performance issues.  These issues
are inherent in gapless numbering because you can't get a gapless
sequence when things roll back without such locks.


Actually, another approach that allows parallel transactions is (at 
least theoretically) possible. You can hand out IDs as transactions 
request them, and if a transaction rolls back you can abort it *and* 
*all* *transactions* *given* *higher* *IDs*, then re-issue the lot. I 
guess that could be useful if transaction failure was extremely unlikely 
and you needed to have lots of work in flight at once.


In practice I don't think it'd be very useful to do this, because 
transactions would still have to commit in the order they obtained IDs 
in, so a slow or blocked transaction would still stall the system just 
like it does with lock-based gapless numbering. Also, once a later 
transaction had obtained an ID prior transactions couldn't obtain any 
more IDs.


I'm not sure this is possible in Pg without modifying the server, 
either. It'd be kind of interesting in a useless-toy-project kind of way.


--
Craig Ringer

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Dmitry Koterov
Hello.

I need to create an auto-increment field on a table WITHOUT using sequences:

CREATE TABLE tbl(
  name TEXT,
  uniq_id INTEGER
);

Each INSERT to this table must generate a new uniq_id which is distinct from
all others.

The problem is that these INSERTs are rolled back oftenly (i.e. they are
executed within a transaction block which is rolled back time to time), this
is an existing design of the current architecture and unfortunately we have
to live with it. And I need as compact uniq_id generation (with minimum
holes) as it possible - this is a VERY important requirement (to export
these values into external systems which accepts only IDs limited from 1 to
10).

So I cannot use sequences: sequence value is obviously not rolled back, so
if I insert nextval(...) as uniq_id, I will have large holes (because of
often transaction rollbacks) and exhaust 10 uniq_ids very fast. How to
deal with all this without sequences?

I tried

BEGIN;
LOCK TABLE tbl;
INSERT INTO tbl(uniq_id) VALUES((SELECT max(uniq_id) FROM tbl) + 1);
COMMIT;

but seems it performs too hard locking - time to time this query is timed
out (or sometimes deadlocks with other queries).

Is there any other, less hard, locking which allow me to guarantee that no
INSERTs will be performed into tbl between max() calculation and UPDATE
query itself, but does not lock the whole table?


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread salah jubeh

 Hello,

This is an ugly hack. Try to have a temporary holder that carries the maximum 
value. for example create a table with a  one columnn and certainly one row 
and synchronize this value with your sequence

Regards






From: Dmitry Koterov dmi...@koterov.ru
To: Postgres General pgsql-general@postgresql.org
Sent: Thu, June 30, 2011 8:40:39 PM
Subject: [GENERAL] How to create auto-increment field WITHOUT a sequence 
object?


Hello.

I need to create an auto-increment field on a table WITHOUT using sequences:

CREATE TABLE tbl(
  name TEXT,
  uniq_id INTEGER
);

Each INSERT to this table must generate a new uniq_id which is distinct from 
all 
others. 

The problem is that these INSERTs are rolled back oftenly (i.e. they are 
executed within a transaction block which is rolled back time to time), this is 
an existing design of the current architecture and unfortunately we have to 
live 
with it. And I need as compact uniq_id generation (with minimum holes) as it 
possible - this is a VERY important requirement (to export these values into 
external systems which accepts only IDs limited from 1 to 10). 

So I cannot use sequences: sequence value is obviously not rolled back, so if I 
insert nextval(...) as uniq_id, I will have large holes (because of often 
transaction rollbacks) and exhaust 10 uniq_ids very fast. How to deal with 
all this without sequences?

I tried

BEGIN;
LOCK TABLE tbl;
INSERT INTO tbl(uniq_id) VALUES((SELECT max(uniq_id) FROM tbl) + 1);
COMMIT;

but seems it performs too hard locking - time to time this query is timed out 
(or sometimes deadlocks with other queries).

Is there any other, less hard, locking which allow me to guarantee that no 
INSERTs will be performed into tbl between max() calculation and UPDATE query 
itself, but does not lock the whole table?

Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread A.M.

On Jun 30, 2011, at 2:40 PM, Dmitry Koterov wrote:

 Hello.
 
 I need to create an auto-increment field on a table WITHOUT using sequences:

This problem pops up a lot for invoice sequence numbers for the tax office and 
related cases. (Search for gapless sequence.) 

Since the numbers are really only needed for an external system (as you 
mention), then it may make sense to generate the gapless IDs when necessary and 
map the generated IDs to the rows later. The drawback is that some rows in the 
table will not have the gapless ID until the batch job is run, but all rows 
will still be addressable by the real sequence ID.

Cheers,
M



-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Dmitry Koterov
Thank you.

It may not be fully gapless. The main cause is to keep uniq_id as low as
it could be to not to exhaust 10 values too fast.
I think solutions with addition tables look too complicated for this case,
is there a possiblilty to not to use an additional table?

On Thu, Jun 30, 2011 at 10:55 PM, A.M. age...@themactionfaction.com wrote:


 On Jun 30, 2011, at 2:40 PM, Dmitry Koterov wrote:

  Hello.
 
  I need to create an auto-increment field on a table WITHOUT using
 sequences:

 This problem pops up a lot for invoice sequence numbers for the tax office
 and related cases. (Search for gapless sequence.)

 Since the numbers are really only needed for an external system (as you
 mention), then it may make sense to generate the gapless IDs when necessary
 and map the generated IDs to the rows later. The drawback is that some rows
 in the table will not have the gapless ID until the batch job is run, but
 all rows will still be addressable by the real sequence ID.

 Cheers,
 M



 --
 Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
 To make changes to your subscription:
 http://www.postgresql.org/mailpref/pgsql-general



Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread David Johnston
From: pgsql-general-ow...@postgresql.org
[mailto:pgsql-general-ow...@postgresql.org] On Behalf Of Dmitry Koterov
Sent: Thursday, June 30, 2011 2:41 PM
To: Postgres General
Subject: [GENERAL] How to create auto-increment field WITHOUT a sequence
object?

 

Hello.

 

I need to create an auto-increment field on a table WITHOUT using sequences:

 

CREATE TABLE tbl(

  name TEXT,

  uniq_id INTEGER

);

 

Each INSERT to this table must generate a new uniq_id which is distinct from
all others. 

 

The problem is that these INSERTs are rolled back oftenly (i.e. they are
executed within a transaction block which is rolled back time to time), this
is an existing design of the current architecture and unfortunately we have
to live with it. And I need as compact uniq_id generation (with minimum
holes) as it possible - this is a VERY important requirement (to export
these values into external systems which accepts only IDs limited from 1 to
10). 

 

So I cannot use sequences: sequence value is obviously not rolled back, so
if I insert nextval(...) as uniq_id, I will have large holes (because of
often transaction rollbacks) and exhaust 10 uniq_ids very fast. How to
deal with all this without sequences?

 

I tried

 

BEGIN;

LOCK TABLE tbl;

INSERT INTO tbl(uniq_id) VALUES((SELECT max(uniq_id) FROM tbl) + 1);

COMMIT;

 

but seems it performs too hard locking - time to time this query is timed
out (or sometimes deadlocks with other queries).

 

Is there any other, less hard, locking which allow me to guarantee that no
INSERTs will be performed into tbl between max() calculation and UPDATE
query itself, but does not lock the whole table?

 

 

 

Why not have an internal and an external id?  The internal one would use the
sequence and wouldn't care about being gap-less.  The external one would be
assigned post-Insert and thus, ignoring deletes, can be gap-less.  Depending
upon how frequently/quickly the external identifier needs to be present you
have various options to actually assign the external identifier value.

 

CREATE TABLE tbl(

name TEXT,

uniq_id serial,

external_id integer NULL

);

 

Upon creating a new record you have a record with a NULL external_id.  At
some point in the future, prior to export, you can replace all the NULLs
with actual values using a sequence.  Depending on whether or not the
transaction can be rolled back when successful you can add the UPDATE
statement as the last statement of the transaction so that it will only fire
if the transaction is otherwise going to complete successfully.

 

Without more detail about the how and why of your restrictions it is
difficult to provide solutions.

 

David J.

 



Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread George Weaver

Original Message From: Dmitry Koterov


I need to create an auto-increment field on a table WITHOUT using 
sequences:


You may get some ideas at http://www.varlena.com/GeneralBits/130.php

George 



--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Dmitry Koterov
Hello.

I need to create an auto-increment field on a table WITHOUT using sequences:

CREATE TABLE tbl(
  name TEXT,
  uniq_id INTEGER
);

Each INSERT to this table must generate a new uniq_id which is distinct from
all others.

The problem is that these INSERTs are rolled back oftenly (i.e. they are
executed within a transaction block which is rolled back time to time), this
is an existing design of the current architecture and unfortunately we have
to live with it. And I need as compact uniq_id generation (with minimum
holes) as it possible - this is a VERY important requirement (to export
these values into external systems which accepts only IDs limited from 1 to
10).

So I cannot use sequences: sequence value is obviously not rolled back, so
if I insert nextval(...) as uniq_id, I will have large holes (because of
often transaction rollbacks) and exhaust 10 uniq_ids very fast. How to
deal with all this without sequences?

I tried

BEGIN;
LOCK TABLE tbl;
INSERT INTO tbl(uniq_id) VALUES((SELECT max(uniq_id) FROM tbl) + 1);
COMMIT;

but seems it performs too hard locking - time to time this query is timed
out (or sometimes deadlocks with other queries).

Is there any other, less hard, locking which allow me to guarantee that no
INSERTs will be performed into tbl between max() calculation and UPDATE
query itself, but does not lock the whole table?


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Dmitriy Igrishin
Hey Dmitry,

2011/6/30 Dmitry Koterov dmitry.kote...@gmail.com

 Hello.

 I need to create an auto-increment field on a table WITHOUT using
 sequences:

 CREATE TABLE tbl(
   name TEXT,
   uniq_id INTEGER
 );

 Each INSERT to this table must generate a new uniq_id which is distinct
 from all others.

 The problem is that these INSERTs are rolled back oftenly (i.e. they are
 executed within a transaction block which is rolled back time to time), this
 is an existing design of the current architecture and unfortunately we have
 to live with it. And I need as compact uniq_id generation (with minimum
 holes) as it possible - this is a VERY important requirement (to export
 these values into external systems which accepts only IDs limited from 1 to
 10).

 So I cannot use sequences: sequence value is obviously not rolled back, so
 if I insert nextval(...) as uniq_id, I will have large holes (because of
 often transaction rollbacks) and exhaust 10 uniq_ids very fast. How to
 deal with all this without sequences?

 I tried

 BEGIN;
 LOCK TABLE tbl;
 INSERT INTO tbl(uniq_id) VALUES((SELECT max(uniq_id) FROM tbl) + 1);
 COMMIT;


Consider to create table with column of type integer and
write a function which will perform SELECT FOR UPDATE ...
and returns the next value, i.e.
BEGIN;
INSERT INTO tbl(uniq_id) SELECT uniq_id_generator(); -- SELECT FOR UPDATE
inside
COMMIT; -- or ROLLBACK

-- 
// Dmitriy.


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Scott Marlowe
On Thu, Jun 30, 2011 at 12:40 PM, Dmitry Koterov dmi...@koterov.ru wrote:
 Hello.
 I need to create an auto-increment field on a table WITHOUT using sequences:
 CREATE TABLE tbl(
   name TEXT,
   uniq_id INTEGER
 );
 Each INSERT to this table must generate a new uniq_id which is distinct from
 all others.

Do they need to be in order?  It looks like you only need a few since
the range you mention is 1 to 10.  you could put those numbers in
another table.  Then in a transaction you grab a number from the
table, try to delete it.  If it's not there you lost a race condition,
exit and try it again.  If you can delete it then you try the insert
transaction.  If it fails things roll back and the lock on the row is
released.  If the transaction works you commit the whole thing.

Are the transactions really long running?

-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Dmitry Koterov
Thanks to all, I'll try to live with this solution.
(It is not ideal, but pretty good for my case.)

The better way may be to create an additional table with ANY structure and
no data and LOCK using it, but not the tbl table. It theoretically
decrease race conditions - the only thing which I need is to make mutex
around only one update statement.


On Fri, Jul 1, 2011 at 12:01 AM, Dmitry Koterov dmi...@koterov.ru wrote:

 OK.

 Possible next solution is ON AFTER UPDATE trigger:

 BEGIN
   LOCK TABLE tbl IN SHARE UPDATE EXCLUSIVE MODE;
UPDATE tbl SET uniq_id=(SELECT MAX(uniq_id) + 1 FROM tbl) WHERE id =
 NEW.id;
 END;

 Seems SHARE UPDATE EXCLUSIVE is a minimum locking which conflicts with
 itself and which does not conflict with pg_dump.
 (Unfortunately it conflicts with VACUUM which is performed by autovacuum
 process.)

 SHARE UPDATE EXCLUSIVE is better than default LOCK (which also blocks
 reading).


 On Thu, Jun 30, 2011 at 11:38 PM, A.M. age...@themactionfaction.comwrote:


 On Jun 30, 2011, at 3:36 PM, Dmitry Koterov wrote:

  ...possibly within ON AFTER INSERT trigger:
 
  BEGIN
   pg_advisory_lock(0xDEADBEEF);
   UPDATE tbl SET uniq_id=(SELECT MAX(uniq_id) + 1 FROM tbl) WHERE id =
  NEW.id;
  END;
 
  Would it work without explicit pg_advisory_unlock() - would the locking
 be
  released on COMMIT/ROLLBACK?

 No- advisory locks are managed by the application, so that is exactly what
 you don't want. The exclusive table lock is still exactly what you need
 unless you can postpone the generation of the secondary IDs.

 Cheers,
 M





Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Greg Smith

On 06/30/2011 03:01 PM, Dmitry Koterov wrote:


It may not be fully gapless. The main cause is to keep uniq_id as 
low as it could be to not to exhaust 10 values too fast.
I think solutions with addition tables look too complicated for this 
case, is there a possiblilty to not to use an additional table?


You may think it's possible to build a gapless design that is less 
complicated by writing some application or server code to enforce it.  
You've already tried this and learned that it's much harder than it 
seems.  Doing this correctly without causing timeout and deadlock issues 
is a hard problem.


Meanwhile, generating a gapless translation table that only includes 
things that have been committed is easy, and you're not likely to run 
into really strange and unexpected bugs in that implementation later.


Given those are the two situations you're comparing here, I would say 
using the extra table is less complicated in every way.  Sure, you're 
adding another table, but the process happening against it is really 
easy.  The alternative doesn't have the extra table, but that doesn't 
make it less complicated.  Complexity needs to consider how difficult a 
program is going to be to debug and maintain.  And in those areas, 
making a single table gapless is quite complicated.


--
Greg Smith   2ndQuadrant USg...@2ndquadrant.com   Baltimore, MD
Comprehensive and Customized PostgreSQL Training Classes:
http://www.2ndquadrant.us/postgresql-training/


--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Craig Ringer

On 07/01/2011 02:20 AM, Dmitry Koterov wrote:


The problem is that these INSERTs are rolled back oftenly (i.e. they 
are executed within a transaction block which is rolled back time to 
time), this is an existing design of the current architecture and 
unfortunately we have to live with it. And I need as compact uniq_id 
generation (with minimum holes) as it possible - this is a VERY 
important requirement (to export these values into external systems 
which accepts only IDs limited from 1 to 10).


What you want is often referred to as a gapless sequence. Searching 
the mailing list archives for that will find you lots of information.


but seems it performs too hard locking - time to time this query is 
timed out (or sometimes deadlocks with other queries).
You'll have that problem with any gapless sequence approach. You'll have 
to be prepared to re-try failed transactions after deadlocks, or be 
*extremely* strict about the order in which you perform operations so 
you avoid any deadlocks.


--
Craig Ringer

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] How to create auto-increment field WITHOUT a sequence object?

2011-06-30 Thread Chris Travers
Having done gapless numbering for some users of accounting software,
there are two suggestions I would make.

The first is that any sort of gapless numbering inherently runs into
scalability.  You HAVE to lock relevant records, and this means that
only one insert can run at a time, and it must commit before the next
insert can run.  This means you have to keep your transactions short
and predictable in terms of table order.  The suggestion of using for
update is a good one, but it doesn't entirely get rid of the problem,
which is inherent in ensuring gapless numbering in a system with
concurrent transactions.

The second is that you absolutely should use this approach as rarely
as you can get away with.  If it isn't required, don't use it!

Best Wishes,
Chris Travers

-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general