Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL - disabling constraints

I have a table with approx 5 million rows which has a fk constraint referencing the primary key of another table (also approx 5 million rows).

I need to delete about 75000 rows from both tables. I know that if I try doing this with the fk constraint enabled it's going to take an unacceptable amount of time.

Coming from an Oracle background my first thought was to disable the constraint, do the delete & then reenable the constraint. PostGres appears to let me disable constraint triggers if I am a super user (I'm not, but I am logging in as the user that owns/created the objects) but that doesn't seem to be quite what I want.

The other option is to drop the constraint and then reinstate it. I'm worried that rebuilding the constraint is going to take ages given the size of my tables.

Any thoughts?

edit: after Billy's encouragement I've tried doing the delete without changing any constraints and it takes in excess of 10 minutes. However, I have discovered that the table from which I'm trying to delete has a self referential foreign key ... duplicated (& non indexed).

Final update - I dropped the self referential foreign key, did my delete and added it back in. Billy's right all round but unfortunately I can't accept his comment as the answer!

like image 337
azp74 Avatar asked Apr 21 '10 02:04

azp74


People also ask

How do I drop a constraint in PostgreSQL?

The syntax for dropping a unique constraint in PostgreSQL is: ALTER TABLE table_name DROP CONSTRAINT constraint_name; table_name.

What is exclusion constraint in PostgreSQL?

EXCLUSION Constraint − The EXCLUDE constraint ensures that if any two rows are compared on the specified column(s) or expression(s) using the specified operator(s), not all of these comparisons will return TRUE.

How do I drop a foreign key in PostgreSQL?

To drop a foreign key from a table, use the ALTER TABLE clause with the name of the table (in our example, student ) followed by the clause DROP CONSTRAINT with the name of the foreign key constraint. In our example, the name of this constraint is fk_student_city_id .


2 Answers

Per previous comments, it should be a problem. That said, there is a command that may be what you're looking to - it'll set the constraints to deferred so they're checked on COMMIT, not on every delete. If you're doing just one big DELETE of all the rows, it won't make a difference, but if you're doing it in pieces, it will.

SET CONSTRAINTS ALL DEFERRED 

is what you are looking for in that case. Note that constraints must be marked as DEFERRABLE before they can be deferred. For example:

ALTER TABLE table_name   ADD CONSTRAINT constraint_uk UNIQUE(column_1, column_2)   DEFERRABLE INITIALLY IMMEDIATE; 

The constraint can then be deferred in a transaction or function as follows:

CREATE OR REPLACE FUNCTION f() RETURNS void AS $BODY$ BEGIN   SET CONSTRAINTS ALL DEFERRED;    -- Code that temporarily violates the constraint...   -- UPDATE table_name ... END; $BODY$   LANGUAGE plpgsql VOLATILE   COST 100; 
like image 112
Magnus Hagander Avatar answered Sep 17 '22 18:09

Magnus Hagander


What worked for me was to disable one by one the TRIGGERS of those tables that are gonna be involved in the DELETE operation.

ALTER TABLE reference DISABLE TRIGGER ALL; DELETE FROM reference WHERE refered_id > 1; ALTER TABLE reference ENABLE TRIGGER ALL; 

Solution is working in version 9.3.16. In my case time went from 45 minutes to 14 seconds executing DELETE operations.

As stated in the comments section by @amphetamachine, you will need to have admin privileges to the tables to perform this task.

like image 20
gersonZaragocin Avatar answered Sep 16 '22 18:09

gersonZaragocin