Thread: Best way to create unique primary keys across schemas?

Best way to create unique primary keys across schemas?

From
panam
Date:
Hi,

If I'd like to have primary keys generated ("numeric" style, no UUIDs) that
are unique across schemas is the best option to allocate a fixed sequence
range (min,max) to the sequences of all schemas?

Thanks
panam

--
View this message in context:
http://postgresql.1045698.n5.nabble.com/Best-way-to-create-unique-primary-keys-across-schemas-tp5165043p5165043.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

Re: Best way to create unique primary keys across schemas?

From
Scott Marlowe
Date:
On Sun, Jan 22, 2012 at 5:19 PM, panam <panam@gmx.net> wrote:
> Hi,
>
> If I'd like to have primary keys generated ("numeric" style, no UUIDs) that
> are unique across schemas is the best option to allocate a fixed sequence
> range (min,max) to the sequences of all schemas?

That's how I do it.  If you use a bigserial / bigint for it, then the
space is usually plenty big for each schema.

Re: Best way to create unique primary keys across schemas?

From
Chris Angelico
Date:
On Mon, Jan 23, 2012 at 11:19 AM, panam <panam@gmx.net> wrote:
> Hi,
>
> If I'd like to have primary keys generated ("numeric" style, no UUIDs) that
> are unique across schemas is the best option to allocate a fixed sequence
> range (min,max) to the sequences of all schemas?

You can "share" a sequence object between several tables. This can
happen somewhat unexpectedly, as I found out to my surprise a while
ago:

CREATE TABLE tbl1 (ID serial primary key,foo varchar,bar varchar);
INSERT INTO tbl1 (foo,bar) VALUES ('asdf','qwer');
CREATE TABLE tbl2 LIKE tbl1 INCLUDING ALL;
INSERT INTO tbl2 (foo,bar) VALUES ('hello','world');

Both tables will be drawing IDs from the same sequence object, because
"create table like" copies the default value, not the "serial"
shorthand. (It makes perfect sense, it just surprised me that the IDs
were looking a little odd.)

Chris Angelico

Re: Best way to create unique primary keys across schemas?

From
panam
Date:
Chris Angelico wrote
>
>
> You can "share" a sequence object between several tables. This can
> happen somewhat unexpectedly, as I found out to my surprise a while
> ago:
>
> CREATE TABLE tbl1 (ID serial primary key,foo varchar,bar varchar);
> INSERT INTO tbl1 (foo,bar) VALUES ('asdf','qwer');
> CREATE TABLE tbl2 LIKE tbl1 INCLUDING ALL;
> INSERT INTO tbl2 (foo,bar) VALUES ('hello','world');
>
> Both tables will be drawing IDs from the same sequence object, because
> "create table like" copies the default value, not the "serial"
> shorthand. (It makes perfect sense, it just surprised me that the IDs
> were looking a little odd.)
>
Wow, this is pretty useful. Just to fit it more to my original use case, I
used this:

CREATE schema schema1;
CREATE schema schema2;
CREATE TABLE tbl (ID serial primary key,foo varchar,bar varchar);  --in
public schema
CREATE TABLE schema1.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
sequence in public schema
CREATE TABLE schema2.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
sequence in public schema
INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');
INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');

Thanks, I now consider this my best practice. This way, I don't have to
allocate ranges any more a priori :)

--
View this message in context:
http://postgresql.1045698.n5.nabble.com/Best-way-to-create-unique-primary-keys-across-schemas-tp5165043p5281409.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

Re: Best way to create unique primary keys across schemas?

From
Chris Angelico
Date:
On Tue, Jan 24, 2012 at 10:23 PM, panam <panam@gmx.net> wrote:
> Wow, this is pretty useful. Just to fit it more to my original use case, I
> used this:
>
> CREATE TABLE tbl (ID serial primary key,foo varchar,bar varchar);  --in
> public schema
> CREATE TABLE schema1.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
> sequence in public schema
> CREATE TABLE schema2.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
> sequence in public schema
>
> Thanks, I now consider this my best practice. This way, I don't have to
> allocate ranges any more a priori :)

I would recommend using an explicit sequence object rather than
relying on odd behavior like this; for instance, if you now drop
public.tbl, the sequence will be dropped too. However, what you have
there is going to be pretty close to the same result anyway.

As someone who's moved from DB2 to MySQL (hey, it's all open source!)
to Postgres (hey, it's all the features of DB2 and it's _still_ open
source!), I've been pretty pleased with Postgres sequences. Instead of
special-casing the primary key (as MySQL does with auto_increment),
Postgres allows you to have any sequences you like, going any
direction you like, and have multiple in the same table if you so
desire. Incidentally - I've yet to need it, but I think it's possible
to reset a sequence object to start producing lower numbers again,
while your table still has some higher numbers in it (of course being
careful not to get pkey collisions).

ChrisA

Re: Best way to create unique primary keys across schemas?

From
panam
Date:
Chris Angelico wrote
>
> I would recommend using an explicit sequence object rather than
> relying on odd behavior like this; for instance, if you now drop
> public.tbl, the sequence will be dropped too. However, what you have
> there is going to be pretty close to the same result anyway.
>
Oops, thanks for the warning. Any means to prevent accidently dropping the
sequence by deleting the corresponding "root"-table?
What do you mean with "explicit sequence object"? An own sequence for each
table per schema?


Chris Angelico wrote
>
> I think it's possible
> to reset a sequence object to start producing lower numbers again,
> while your table still has some higher numbers in it (of course being
> careful not to get pkey collisions).
>
Yes, this is definitely possible
(http://www.postgresql.org/docs/9.1/static/sql-altersequence.html)


--
View this message in context:
http://postgresql.1045698.n5.nabble.com/Best-way-to-create-unique-primary-keys-across-schemas-tp5165043p5428997.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

Re: Best way to create unique primary keys across schemas?

From
Merlin Moncure
Date:
On Tue, Jan 24, 2012 at 5:23 AM, panam <panam@gmx.net> wrote:
> Wow, this is pretty useful. Just to fit it more to my original use case, I
> used this:
>
> CREATE schema schema1;
> CREATE schema schema2;
> CREATE TABLE tbl (ID serial primary key,foo varchar,bar varchar);  --in
> public schema
> CREATE TABLE schema1.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
> sequence in public schema
> CREATE TABLE schema2.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
> sequence in public schema
> INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
> INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');
> INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
> INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');
>
> Thanks, I now consider this my best practice. This way, I don't have to
> allocate ranges any more a priori :)

Another quirky way to do it is with domains;

create sequence global_seq;
create domain gid bigint default nextval('global_seq');
create table foo (gid gid, f1 text);
create table bar (gid gid, f2 int);
etc.

This looks very appealing on the surface but domains have some quirks
that should give pause.  In particular, you can't make arrays of them,
although you can make arrays of rowtypes that have a domain in them.

Barring domains, you can just manually apply the default instead of
using a serial type:

create table foo (gid bigint default nextval('global_seq'));

merlin

Re: Best way to create unique primary keys across schemas?

From
Rob Sargent
Date:

On 01/24/2012 04:23 PM, Merlin Moncure wrote:
> On Tue, Jan 24, 2012 at 5:23 AM, panam <panam@gmx.net> wrote:
>> Wow, this is pretty useful. Just to fit it more to my original use case, I
>> used this:
>>
>> CREATE schema schema1;
>> CREATE schema schema2;
>> CREATE TABLE tbl (ID serial primary key,foo varchar,bar varchar);  --in
>> public schema
>> CREATE TABLE schema1.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
>> sequence in public schema
>> CREATE TABLE schema2.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
>> sequence in public schema
>> INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
>> INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');
>> INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
>> INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');
>>
>> Thanks, I now consider this my best practice. This way, I don't have to
>> allocate ranges any more a priori :)
> Another quirky way to do it is with domains;
>
> create sequence global_seq;
> create domain gid bigint default nextval('global_seq');
> create table foo (gid gid, f1 text);
> create table bar (gid gid, f2 int);
> etc.
>
> This looks very appealing on the surface but domains have some quirks
> that should give pause.  In particular, you can't make arrays of them,
> although you can make arrays of rowtypes that have a domain in them.
>
> Barring domains, you can just manually apply the default instead of
> using a serial type:
>
> create table foo (gid bigint default nextval('global_seq'));
>
> merlin
>
And UUIDs don't work because....?

Re: Best way to create unique primary keys across schemas?

From
Chris Angelico
Date:
On Wed, Jan 25, 2012 at 9:54 AM, panam <panam@gmx.net> wrote:
> What do you mean with "explicit sequence object"? An own sequence for each
> table per schema?

This:

On Wed, Jan 25, 2012 at 10:23 AM, Merlin Moncure <mmoncure@gmail.com> wrote:
> Barring domains, you can just manually apply the default instead of
> using a serial type:
>
> create table foo (gid bigint default nextval('global_seq'));

http://www.postgresql.org/docs/9.1/static/sql-createsequence.html

When you create a 'serial' column, Postgres creates a sequence and
makes the column as 'int' with a default that pulls from the sequence.
(Similarly for 'bigserial' and 'bigint'.) If you create the sequence
yourself, you get a bit more control over it (eg setting
min/max/step), and can name it appropriately.

Note the OWNED BY clause (as documented in the above link). That's
what I was saying about the sequence being owned by or linked to the
creating table.

ChrisA

Re: Best way to create unique primary keys across schemas?

From
panam
Date:
OK, thanks for replys. To sum up, this is what I now consider best practice:

CREATE schema schema1;
CREATE schema schema2;
CREATE SEQUENCE global_seq; --in public schema
CREATE TABLE tbl (ID bigint default nextval('global_seq') primary key,foo
varchar,bar varchar);  --in public schema
CREATE TABLE schema1.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
sequence in public schema
CREATE TABLE schema2.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
sequence in public schema
INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');
INSERT INTO schema1.tbl (foo,bar) VALUES ('asdf','qwer');
INSERT INTO schema2.tbl (foo,bar) VALUES ('hello','world');

P.S.: This is to figure out good strategies to make pg work with Hibernate
4's multi tenancy feature and I personally dislike handling large UUIDs,
especially during debugging. Plus I see no particular reason to prefer them
over bigint sequences in the general case (but this is a different topic).

--
View this message in context:
http://postgresql.1045698.n5.nabble.com/Best-way-to-create-unique-primary-keys-across-schemas-tp5165043p5430441.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

Re: Best way to create unique primary keys across schemas?

From
Chris Angelico
Date:
On Thu, Jan 26, 2012 at 2:12 AM, panam <panam@gmx.net> wrote:
> CREATE TABLE tbl (ID bigint default nextval('global_seq') primary key,foo
> varchar,bar varchar);  --in public schema
> CREATE TABLE schema1.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
> sequence in public schema
> CREATE TABLE schema2.tbl (LIKE public.tbl INCLUDING ALL);  --draws ids from
> sequence in public schema

Yep, but you can do this more simply:

CREATE TABLE schema1.tbl (ID bigint default nextval('global_seq')
primary key,foo varchar,bar varchar)
CREATE TABLE schema2.tbl (ID bigint default nextval('global_seq')
primary key,foo varchar,bar varchar)

No need for the dummy table.

Obviously you would want better names than these ("global_seq" is a
really dumb name for a production environment!), but you knew that
already :)

ChrisA

Re: Best way to create unique primary keys across schemas?

From
panam
Date:
Thanks, yeah, but the dummy tables are needed anyway in my case for those
entities that are shared among the tenants :)

--
View this message in context:
http://postgresql.1045698.n5.nabble.com/Best-way-to-create-unique-primary-keys-across-schemas-tp5165043p5433562.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

Re: Best way to create unique primary keys across schemas?

From
Chris Angelico
Date:
On Fri, Jan 27, 2012 at 4:56 AM, panam <panam@gmx.net> wrote:
> Thanks, yeah, but the dummy tables are needed anyway in my case for those
> entities that are shared among the tenants :)

Ah! Then that's easy :)

ChrisA

Re: Best way to create unique primary keys across schemas?

From
Jasen Betts
Date:
On 2012-01-23, panam <panam@gmx.net> wrote:
> Hi,
>
> If I'd like to have primary keys generated ("numeric" style, no UUIDs) that
> are unique across schemas is the best option to allocate a fixed sequence
> range (min,max) to the sequences of all schemas?

given that challenge the easiest solution is to just create one
sequence and hang everything off it.

--
⚂⚃ 100% natural