9

I want to alter a table called person and want to add foreign key to it using office table

the query I am using is

ALTER TABLE person
ADD CONSTRAINT person_Office_FK
FOREIGN KEY ( Office_id )
REFERENCES Office ( Office_id ) ;

Table office has around 500,000 rows and table person has around 5 million

This query is taking forever i am not sure what is happening.

4
  • 1
    Forever, that sounds long. Can you be more specific? Commented Aug 7, 2014 at 19:57
  • Btw, I think this is somewhat expected since it needs to cross-check a lot of rows. Commented Aug 7, 2014 at 19:58
  • forever means i am running this query from past 45 minutes, and I am not sure what is going on and how long it is going to take.. Commented Aug 7, 2014 at 20:00
  • 2
    I don't know if MySQL has this, but in MS-SQL you can specify WITH NOCHECK which will create the Foreign Key without checking your existing data to make sure it conforms. It will only apply to future data. Which also means it won't take "forever". Right now your database is checking every row in your person table to make sure it has a matching Office_id in the Office table. Commented Aug 7, 2014 at 20:01

4 Answers 4

7

If Office_id is the primary key of Office, make sure it has a (primary key) index. This will definitely speed up the adding of the constraint.

Also, according to How to temporarily disable a foreign key constraint in MySQL?, you can use

SET FOREIGN_KEY_CHECKS=0;

To disable ALL foreign key constraint checks, possibly this works too when adding them.

Sign up to request clarification or add additional context in comments.

Comments

2

You can use:

SET FOREIGN_KEY_CHECKS=0;

I typically do my own foreign key checking before I do this, though:

SELECT
  Person.*
FROM person
LEFT JOIN Office ON (person.Office_id = Office.Office_id)
WHERE Office.Office_id IS NULL
;

That query should return nothing if you are safe to turn off the FOREIGN_KEY_CHECKS.

Comments

2

The question is still not obsolete. I just got the same issue here and found a workaround in 5 steps:

  1. Duplicate the table: CREATE TABLE table2 LIKE table1;

  2. Apply the constraint foreign key: ALTER TABLE..FOREIGN.... bla bla bla

  3. Dump data from table1 to table2: INSERT INTO table2 SELECT * FROM table1;

  4. Delete table1: DROP TABLE table1;

  5. Rename table2: RENAME TABLE table2 TO table1;

All in one:

CREATE TABLE table2 LIKE table1;
ALTER TABLE..FOREIGN.... bla bla bla;
INSERT INTO table2 SELECT * FROM table1;
DROP TABLE table1;
RENAME TABLE table2 TO table1;

Comments

1

Before adding your constraint, make sure that there's a clustered index on office_id on the office table and a non-clustered index on office_id on the person table.

Remember that every occurrence of office_id on the person table needs to check against every office_id record. This will also speed things up if you ever have to delete an office record.

You don't want to disable the checks, since your constraint will be untrusted and you won't get the performance benefit a foreign key gives you in the query optimizer.

1 Comment

MySQL does not have a concept of trusted/untrusted constraints, such as Microsoft SQL Server has (as of this date).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.