MySQL не может удалить индекс, необходимый в ограничении внешнего ключа

157

Мне нужно изменить мою существующую базу данных, чтобы добавить столбец. Следовательно, я также хочу обновить поле UNIQUE, чтобы охватить этот новый столбец. Я пытаюсь удалить текущий индекс, но получаю ошибкуMySQL Cannot drop index needed in a foreign key constraint

CREATE TABLE mytable_a (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;

CREATE TABLE mytable_b (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;

CREATE TABLE mytable_c (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;


CREATE TABLE `mytable` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `AID` tinyint(5) NOT NULL,
  `BID` tinyint(5) NOT NULL,
  `CID` tinyint(5) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `AID` (`AID`,`BID`,`CID`),
  KEY `BID` (`BID`),
  KEY `CID` (`CID`),
  CONSTRAINT `mytable_ibfk_1` FOREIGN KEY (`AID`) REFERENCES `mytable_a` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mytable_ibfk_2` FOREIGN KEY (`BID`) REFERENCES `mytable_b` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mytable_ibfk_3` FOREIGN KEY (`CID`) REFERENCES `mytable_c` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB;




mysql> ALTER TABLE mytable DROP INDEX AID;
ERROR 1553 (HY000): Cannot drop index 'AID': needed in a foreign key constraint
user391986
источник
Предполагая UNIQUE KEY AIDна mytable?
Майк Перселл

Ответы:

229

Вы должны сбросить внешний ключ. Внешние ключи в MySQL автоматически создают индекс для таблицы (был задан вопрос SO ).

ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ; 
Брайан Фишер
источник
12
Возможно, вы захотите добавить его обратно после mytableудаления индекса: ALTER TABLE ADD CONSTRAINT mytable_ibfk_1FOREIGN KEY ( AID) REFERENCES mytable_a( ID) ON DELETE CASCADE;
laffuste
8
Это здорово, но что я могу сделать, если мое FOREIGN KEYограничение было анонимным?
Пехат
@Pehat, проверьте мой ответ ниже stackoverflow.com/a/54145440/2305119
тизз
1
Примечание: внешний ключ может быть не таким очевидным. Чтобы найти все внешние ключи, относящиеся к таблице и столбцу, вы можете использовать этот запрос: dba.stackexchange.com/questions/102371/…
charlax
84

Шаг 1

Перечислите внешний ключ (обратите внимание, что он отличается от имени индекса)

SHOW CREATE TABLE  <Table Name>

Результат покажет вам имя внешнего ключа.

Формат:

CONSTRAINT `FOREIGN_KEY_NAME` FOREIGN KEY (`FOREIGN_KEY_COLUMN`) REFERENCES `FOREIGN_KEY_TABLE` (`id`),

Шаг 2

Drop (внешний / первичный / ключ) ключ

ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign key name>

Шаг 3

Брось индекс.

Абхишек Гоэль
источник
18

Если вы имеете в виду, что вы можете сделать это:

CREATE TABLE mytable_d (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;


ALTER TABLE mytable
ADD COLUMN DID tinyint(5) NOT NULL,
ADD CONSTRAINT mytable_ibfk_4 
      FOREIGN KEY (DID) 
        REFERENCES mytable_d (ID) ON DELETE CASCADE;

 > OK.

Но потом:

ALTER TABLE mytable
DROP KEY AID ;

дает ошибку.


Вы можете удалить индекс и создать новый в одном ALTER TABLEвыражении:

ALTER TABLE mytable
DROP KEY AID ,
ADD UNIQUE KEY AID (AID, BID, CID, DID);
ypercubeᵀᴹ
источник
8

Поскольку у вас должен быть индекс для поля внешнего ключа, вы можете просто создать простой индекс для поля «AID».

CREATE INDEX aid_index ON mytable (AID);

и только потом сбросить уникальный индекс 'AID'

ALTER TABLE mytable DROP INDEX AID;
Эли Д.М.
источник
7

Внешний ключ всегда требует индекса. Без индекса, обеспечивающего ограничение, потребовалось бы полное сканирование таблицы в ссылочной таблице для каждого вставленного или обновленного ключа в ссылочной таблице. И это будет иметь недопустимое влияние на производительность. Это имеет следующие 2 последствия:

  • При создании внешнего ключа база данных проверяет, существует ли индекс. Если не индекс будет создан. По умолчанию оно будет иметь то же имя, что и ограничение.
  • Когда есть только один индекс, который можно использовать для внешнего ключа, его нельзя удалить. Если вы действительно не хотите его отбрасывать, вам нужно либо удалить ограничение внешнего ключа, либо сначала создать для него другой индекс.
Стефан Монделерс
источник
1
у вас есть теория, что других ответов не хватало.
Деннис
1
Итак: если у вас есть составной уникальный индекс (несколько столбцов в уникальном ограничении), вы не можете удалить уникальный ключ AB, если у вас нет индекса для A и B. Если вы получаете эту ошибку, другая таблица использует индекс столбца A или B, и вам придется добавить их, прежде чем вы сможете безопасно удалить AB уникальный.
Робин Де
@RobinDeSchepper Хорошее замечание. И при использовании составных уникальных индексов порядок полей не важен для уникального индекса, но он может быть важен для внешнего ключа. Уникальный индекс на A, B может использоваться внешним ключом на A, но не внешним ключом на B.
Стефан Монделаерс
2

Я думаю, что это простой способ отбросить индекс.

set FOREIGN_KEY_CHECKS=1;

ALTER TABLE mytable DROP INDEX AID;

set FOREIGN_KEY_CHECKS=0;
Рам Э Ш
источник
2
Я думаю, что вы обменялись включением и отключением проверок. На вершине я бы ожидал FOREIGN_KEY_CHEK=0и в конце FOREIGN_KEY_CHEK=1.
Ром
0

В моем случае я удалил внешний ключ и все еще не мог удалить индекс. Это было потому, что была еще одна таблица с внешним ключом этой таблицы в тех же полях. После того, как я удалил внешний ключ в другой таблице, я мог удалить индексы в этой таблице.

яв
источник
0

Если вы хотите удалить столбец с внешним ключом (с ограничением), сначала вы должны удалить внешний ключ, а затем удалить столбец. Когда вы удаляете внешний ключ, вам не нужно передавать все имя, просто передайте внешний ключ. имя столбца:

$table->dropForeign(['currency_id']);
$table->dropColumn('currency_id');

более подробная информация о:

https://laravel.com/docs/6.x/migrations#foreign-key-constraints

OMR
источник