Why does Postgres create multiple indexes on the primary key by default? - postgresql

From the docs: "PostgreSQL automatically creates a unique index when a unique constraint or primary key is defined for a table."
In my table notifications, I set the id column as the primary key. When I take a look at the indexes on the table using \d notifications the output is:
Indexes:
"notifications_pkey" PRIMARY KEY, btree (id)
"notifications_unique_id" UNIQUE CONSTRAINT, btree (id)
Does this mean I have two indexes on the same column? If so - why does PG do this by default?
Also - does this mean that all my indexes should have this constraint?

Related

postgres indexing all columns of composite primary key

in postgres, just checking if we need to index all columns of composite primary key
CREATE TABLE BOOK_TYPE(
ID TEXT NOT NULL,
TYPE TEXT NOT NULL,
LABELS HSTORE NOT NULL,
CONSTRAINT BOOK_TYPE_PKEY PRIMARY KEY (ID,TYPE)
);
should I have to index ID and type separately?
You don't need to create any extra index unless you happen to need it to speed up a query. The primary key will automatically create a unique index on (id, type), and that is all that is needed to guarantee consistency.

Automatically created indexes in postgresql: combined index on key attributes?

I'm not sure which indexes postgresql AUTOMATICALLY creates; I think it will create one on Book(ibsn), because its the primary key, and also Book(title), because its a candidate key... but I'm not sure if postgres will automatically create a combined index on all key attributes Book(ibsn, title). Also, would it create any other indexes automatically?
CREATE TABLE Book (
isbn INTEGER CONSTRAINT B_ISBN CHECK (ISBN BETWEEN 1 AND 2000),
title VARCHAR(200) CONSTRAINT B_TITLE NOT NULL UNIQUE,
author VARCHAR(50) CONSTRAINT B_AUTH NOT NULL,
cost FLOAT DEFAULT 0.00,
lent_date DATE,
returnDate DATE,
times_lent INTEGER,
sectionID SMALLINT,
CONSTRAINT BOOK_PRIME PRIMARY KEY (isbn),
CONSTRAINT BOOK_SECT FOREIGN KEY (sectionID) REFERENCES Section(sectionID) ON DELETE CASCADE
);
Postgres will automatically create indexes only for:
primary keys: Adding a primary key will automatically create a unique B-tree index on the column or group of columns listed in the primary key
unique constraints: Adding a unique constraint will automatically create a unique B-tree index on the column or group of columns listed in the constraint
In your case, Postgres creates one unique index on the column isbn and one unique index on the column unique because you declared each column individually to be unique, not the combination of both.
No other indexes will be created automatically.

Postgres - remove unique contraint (does not exist)

I have following table:
I have created unique constraint CREATE UNIQUE INDEX unique_item_media_idx ON mediagalleryitem (article_id, media_id);
Now, I want to remove it and it is impossible for me. When I execute ALTER TABLE "mediagalleryitem" DROP CONSTRAINT unique_item_media_idx; it tells me: constraint "unique_item_media_idx" of relation "mediagalleryitem" does not exist
When I run from CLI \d mediagalleryitem I get:
Indexes:
"mediagalleryitem_pkey" PRIMARY KEY, btree (id)
"unique_item_media_idx" UNIQUE, btree (article_id, media_id)
"idx_1c5848117294869c" btree (article_id)
"idx_1c584811ea9fdd75" btree (media_id)
Foreign-key constraints:
"fk_1c5848117294869c" FOREIGN KEY (article_id) REFERENCES article(id)
"fk_1c584811ea9fdd75" FOREIGN KEY (media_id) REFERENCES media(id)
Whwere is the problem?
What you have there is an index, not a constraint. You can drop it using DROP INDEX unique_item_media_idx. Just as you created an index, you remove an index.

Will a primary key index serve as an index for a foreign key when fk columns are subset of pk?

I have a table where part of the primary key is a foreign key to another table.
create table player_result (
event_id integer not null,
pub_time timestamp not null,
name_key varchar(128) not null,
email_address varchar(128),
withdrawn boolean not null,
place integer,
realized_values hstore,
primary key (event_id, pub_time, name_key),
foreign key (email_address) references email(address),
foreign key (event_id, pub_time) references event_publish(event_id, pub_time));
Will the index generated for the primary key suffice to back the foreign key on event_id and pub_time?
Yes.
Index A,B,C
is good for:
A
A,B
A,B,C (and any other combination of the full 3 fields, if default order is unimportant)
but not good for other combinations (such as B,C, C,A etc.).
It will be useful for the referencing side, such that a DELETE or UPDATE on the referenced table can use the PRIMARY KEY of the referencing side as an index when performing checks for the existence of referencing rows or running cascade update/deletes. PostgreSQL doesn't require this index to exist at all, it just makes foreign key constraint checks faster if it is there.
It is not sufficient to serve as the unique constraint for a reference to those columns. You couldn't create a FOREIGN KEY that REFERENCES player_result(event_id, pub_time) because there is no unique constraint on those columns. That pair can appear multiple times in the table so long as each pair has a different name_key.
As #xagyg accurately notes, the unique b-tree index created by the foreign key reference is also only useful for references to columns from the left of the index. It could not be used for a lookup of pub_time, name_key or just name_key, for example.

Adding primary key changes column type

Our database currently doesn't define primary keys on any tables. All of the id columns are simply unique indexes. I'm dropping those indexes and replacing them with proper primary keys.
My problem: In Postgres 8.4.7, one table in particular changes the data type from bigint to integer when I add the primary key to the table.
I've got the following table definition:
psql=# \d events
Table "public.events"
Column | Type | Modifiers
-----------------------+--------------------------+-----------------------------------------------------
id | bigint | not null default nextval('events_id_seq'::regclass)
[more columns omitted]
Indexes:
"events_id_unique_pk" UNIQUE, btree (id)
Foreign-key constraints:
"events_clearing_event_ref_fk" FOREIGN KEY (clearing_event_id) REFERENCES events(id)
"events_event_configs_id_fk" FOREIGN KEY (event_config_id) REFERENCES event_configs(id)
"events_pdu_circuitbreaker_id_fk" FOREIGN KEY (pdu_circuitbreaker_id) REFERENCES pdu_circuitbreaker(id)
"events_pdu_id_fk" FOREIGN KEY (pdu_id) REFERENCES pdus(id) ON DELETE CASCADE
"events_pdu_outlet_id_fk" FOREIGN KEY (pdu_outlet_id) REFERENCES pdu_outlet(id)
"events_sensor_id_fk" FOREIGN KEY (sensor_id) REFERENCES sensors(id)
"events_user_id_fk" FOREIGN KEY (clearing_user_id) REFERENCES users(id)
Referenced by:
TABLE "events" CONSTRAINT "events_clearing_event_ref_fk" FOREIGN KEY (clearing_event_id) REFERENCES events(id)
TABLE "event_params" CONSTRAINT "events_params_event_id_fk" FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE
Triggers:
event_validate BEFORE INSERT OR UPDATE ON events FOR EACH ROW EXECUTE PROCEDURE event_validate()
This is what happens:
psql=# ALTER TABLE events ADD PRIMARY KEY (id);
NOTICE: ALTER TABLE / ADD PRIMARY KEY will create implicit index "events_pkey" for table "events"
ALTER TABLE
psql=# \d events
Table "public.events"
Column | Type | Modifiers
-----------------------+--------------------------+-----------------------------------------------------
id | integer | not null default nextval('events_id_seq'::regclass)
[more columns omitted]
Indexes:
"events_pkey" PRIMARY KEY, btree (id)
"events_id_unique_pk" UNIQUE, btree (id)
Foreign-key constraints:
"events_clearing_event_ref_fk" FOREIGN KEY (clearing_event_id) REFERENCES events(id)
"events_event_configs_id_fk" FOREIGN KEY (event_config_id) REFERENCES event_configs(id)
"events_pdu_circuitbreaker_id_fk" FOREIGN KEY (pdu_circuitbreaker_id) REFERENCES pdu_circuitbreaker(id)
"events_pdu_id_fk" FOREIGN KEY (pdu_id) REFERENCES pdus(id) ON DELETE CASCADE
"events_pdu_outlet_id_fk" FOREIGN KEY (pdu_outlet_id) REFERENCES pdu_outlet(id)
"events_sensor_id_fk" FOREIGN KEY (sensor_id) REFERENCES sensors(id)
"events_user_id_fk" FOREIGN KEY (clearing_user_id) REFERENCES users(id)
Referenced by:
TABLE "events" CONSTRAINT "events_clearing_event_ref_fk" FOREIGN KEY (clearing_event_id) REFERENCES events(id)
TABLE "event_params" CONSTRAINT "events_params_event_id_fk" FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE
Triggers:
event_validate BEFORE INSERT OR UPDATE ON events FOR EACH ROW EXECUTE PROCEDURE event_validate()
I considered a few workarounds, but I'd really rather know why it's happening. There are a few other tables that also use bigint, so I don't want to just hack a solution in place.
This is scripted with Liquibase, but it happens directly in the Postgres console too.
Update
Two other points:
I can create a simple table with a bigint id and a unique index on id, add the primary key, and the column type stays the same.
All tables are empty at the time execution.
Could it have something to do with the constraints?
That's pretty interesting. I can't reproduce it with version 9.1.0 (yes, I should upgrade too!). But then I don't know precisely how the original table and sequence were created.
This page seems to allude to a similar automatic change of types between SERIAL and INTEGER: http://grover.open2space.com/content/migrate-data-postgresql-and-maintain-existing-primary-key
Could it be something like creating the table using SERIAL instead of BIGSERIAL, and then forcing the type to BIGINT? Something in between the sequence and primary key manipulations might have reset it.
I wasn't able to reproduce this the next day, even after reproducing it multiple times with witnesses the first time it occurred. I'm chalking it up to gremlins.