I've created a table for accounts/users with a primary key (UsersID, AccountsID) like below. Should I add the index for the Users table?
create table AccountsUsers
(
AccountsID int unsigned not null,
UsersID int unsigned not null,
Roles bigint unsigned null,
primary key (UsersID, AccountsID),
constraint AccountsUsers_Accounts_ID_fk
foreign key (AccountsID) references Accounts (ID)
on update cascade on delete cascade,
constraint AccountsUsers_Users_ID_fk
foreign key (UsersID) references Users (ID)
on update cascade on delete cascade
)
engine=InnoDB
;
create index AccountsUsers_Accounts_ID_fk
on AccountsUsers (AccountsID)
;
MySQL will create the necessary indexes for the foreign key automatically, if necessary.
In the case of your foreign key on UsersId, it can use the left column of your primary key. It doesn't need to create a new index for that foreign key.
In the case of your foreign key on AccountsId, MySQL will create a new index automatically. It can't use the fact that AccountsId is part of your primary key, because it isn't the left-most column.
After you do the CREATE TABLE, run SHOW CREATE TABLE AccountsUsers and you should see the new index it created for AccountsId.
From the documentation
MySQL requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
In other words, if you don't already have the required indexes on the columns of your referencing table (AccountsUsers), MySQL will create them for you.
If the columns in the referenced tables (Accounts and Users) are not indexed you will get an error. Your's look like they will be Primary Keys on their respective tables, so you should be fine.
Related
I'm trying to understand the difference between creating a FOREIGN KEY this way:
CREATE TABLE child(
id_child INT NOT NULL,
id_parent INT
FOREIGN KEY(id_parent) REFERENCES parent(id_parent));
rather than this one:
CREATE TABLE child(
id_child INT NOT NULL,
id_parent INT
CONSTRAINT FK_id_parent FOREIGN KEY(id_parent) REFERENCES parent(id_parent));
If I use the first form it will create a CONSTRAINT anyway (Innodb indexes, or am I wrong? not so illustrated about indexes). So, what's the need to explicitly declare the CONSTRAINT or there's no reason to do it?
Using the CONSTRAINT keyword syntax, we can name the constraint according to our chosen convention, rather than having InnoDB use a system assigned name.
That's the only difference.
(Confusingly, the syntax for dropping the foreign key constraint doesn't allow the CONSTRAINT keyword, we have to ALTER TABLE ... DROP FOREIGN KEY foo, where foo is the name of the foreign key constraint, whether we assigned the name or InnoDB generated it.)
Yes, InnoDB automatically creates an index to support the foreign key, if a suitable index isn't already available. If we define an index separately (using KEY indexname (id_parent) for example, then the foreign key constraint can have a different name than the index.
I have a Mysql table having the following structure:
As you can see there is a composite primary key constraint between the fields: word_id and preposition_id.
I want to remove the Primary Key constraint from word_id without touching the preposition_id field, and without losing data from the linked tables (Foreign Key tables). How can I do it?
Regards.
There is no syntax available to modify a constraint and drop only "a half" of the primary key.
You must drop the whole primary key, and then recreate it from scrach.
Just:
ALTER TABLE tablename DROP PRIMARY KEY;
and then:
ALTER TABLE tablename ADD PRIMARY KEY ( preposition_id );
You need first to drop all foreign keys thar reference the primary key in this table.
Data in tables will be preserved.
Is there an improvement in performance in indexing foreign keys in InnoDB? As far as I have read, InnoDB automatically creates an index for the foreign key.
Here is the query given to me for creating the table.
DROP TABLE IF EXISTS `assignments`;
CREATE TABLE `assignments`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user` INTEGER NOT NULL,
`job` INTEGER NOT NULL,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `job_fk1` (`user`),
INDEX `job_fk2` (`job`),
CONSTRAINT `job_fk1`
FOREIGN KEY (`user`)
REFERENCES `users` (`id`),
CONSTRAINT `job_fk2`
FOREIGN KEY (`job`)
REFERENCES `jobs` (`id`)
) ENGINE=InnoDB;
In there, he created foreign keys named job_fk1 and job_fk2. He used the names of these foreign keys as the name of the index.
Is there an improvement in performance in indexing foreign keys in InnoDB?
Answer: No. Performance will be degraded due to duplicate keys.
You do not need
INDEX `job_fk1` (`user`),
INDEX `job_fk2` (`job`),
Those will be automatically created by InnoDB internally. But you need to have index on users (id) and jobs (id) for faster operations on assignments table
http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html
"InnoDB requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist. (This is in contrast to some older versions, in which indexes had to be created explicitly or the creation of foreign key constraints would fail.) index_name, if given, is used as described previously."
You are correct that MySQL will create an index on a column, if it doesn't already exist, when creating a foreign key constraint. However, feel free to create an index on the column and remove the auto-generated one if you want.
You also might want additional multi-column indexes to aid queries like this make-believe one:
SELECT id, user, job
FROM assignments
WHERE job = 5
ORDER BY user
The multi-column index (job, user) would satisfy both the search and the sort, and since secondary indexes include the primary key, it would also act as a covering index in this case.
I need to add a primary key on a table "usernames"
I have 3 columns in it :
userid int(10)
username char(20)
user char(50)
and the primary key is set on 'username' field and i used it as a foreign key to link it to another table. Now i need to add primary key on 'userid' field also... so i tried out :
alter table `usernames` drop primary key, add primary key(userid,username);
and i get an error saying
ERROR 1553 (HY000): Cannot drop index 'PRIMARY":needed in a foreign key constraint
is there any possible way to do this ??
There is:
Drop the FK constraint
Drop PK Constraint
Create New PK
Add Unique Constraint on the name column
Recreate FK
Raj
I assume you use MySql (despite you tag your question as Sql Server).
You can decide to:
Disable all check and try to remove primary key but the new must have the same name
or
Drop foreign key constraints referred to your primary key and then remove your primary key and finally re-add foreign keys
You have to drop the foreign key in order to modify the primary key
As implied by the name, a table can only have at most one PRIMARY key. Whilst it can have other UNIQUE keys, which have a similar effect, they really ought not be used for foreign-key relations.
So, you have two choices:
Retain your existing schema (perhaps username is a perfectly good natural key such that you need not bother with a synthetic one, in which case you can consider dropping the userid column altogether); or
Making userid your PRIMARY key, in which case username should not be used for foreign key relations. I outline below a method for doing this "offline" (where the database is guaranteed not to be altered by any other process during the transition); should you be working "online", you will need to add further steps to ensure integrity is preserved:
Add a new userid column for the foreign key in all child tables and drop the existing foreign key constraint:
ALTER TABLE foo
ADD COLUMN userid INT(10),
DROP FOREIGN KEY fk_name;
Change the primary key in your usernames tables (should you wish for the database to enforce a uniqueness constraint over username, you can define a UNIQUE key instead):
ALTER TABLE usernames
DROP PRIMARY KEY,
ADD PRIMARY KEY (userid),
ADD UNIQUE KEY (username); -- optional
Update the child tables to contain the relevant userid from the parent:
UPDATE foo JOIN usernames USING (username)
SET foo.userid = usernames.userid;
Add the new foreign key constraints and drop the old username columns from the child tables:
ALTER TABLE foo
ADD FOREIGN KEY (userid) REFERENCES usernames (userid),
DROP COLUMN username;
I have to make one of the foreign keys unique. The problem is, I am getting the following message from the phpMyAdmin:
The following indexes appear to be equal and one of them should be removed: consignmentnumber_id_UNIQUE, fk_consignments_consignmentnumbers2
So my question is this: should I be bothered? Is it really important not to have such indexes?
Every column with an key (primary, foreign) needs an index. Same with column being unique. You probably created two indexes (one when creating FK and one on Unique constraint). If this is the case just drop one of those indexes.
It is overhead for the DB to maintain two equivalent indexes.
mysql > create unique index index_bar_id on foos(bar_id);
mysql > alter table foos add constraint index_bar_id foreign key (bar_id) references bars (id);
Read more at http://sixarm.com/about/mysql-create-indexes-foreign-keys-constraints.html
For the future, if you want to make your foreign key unique, you can simply modify your foreign key column like this:
ALTER TABLE your_table
MODIFY COLUMN your_fk_column [INT, VARCHAR etc.][NOT NULL] UNIQUE;
Just so you know, it seems like you can also have UNIQUE foreign keys:
CREATE TABLE user(
uid INT NOT NULL AUTO_INCREMENT,
username VARCHAR(16) NOT NULL UNIQUE,
email_id INT NOT NULL UNIQUE,
FOREIGN KEY (email_id) REFERENCES email(uid)
ON DELETE CASCADE
ON UPDATE CASCADE,
PRIMARY KEY (uid));