MySQL Неможливо знизити індекс, необхідний для обмеження зовнішнього ключа


155

Мені потрібно ВІДНОВИТИ існуючу базу даних, щоб додати стовпець. Отже, я також хочу оновити поле 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

Припустимо, що UNIQUE KEY AIDна mytable?
Майк Перселл

Відповіді:


228

Ви повинні скинути іноземний ключ. Іноземні клавіші в MySQL автоматично створюють індекс на столі (З'явилось ТАКЕ запитання ).

ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ; 

12
Ви можете додати його назад після скидання індексу: ПОДІЛИТИСЯ ТАБЛИЦІ mytableДОДАТИ ОГРАНИЧЕННЯ mytable_ibfk_1ІНОЗЕМНОГО КЛЮЧА ( AID) ДОВІДКИ mytable_a( ID) НА СКАЧАТИ КАСАДУ;
laffuste

8
Це чудово, але що я можу зробити, якщо моє FOREIGN KEYобмеження було анонімним?
Пехат

@Pehat перевірити мою відповідь нижче stackoverflow.com/a/54145440/2305119
thyzz

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

Клавіша випуску (зовнішній / первинний / ключовий)

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);

8

Оскільки у вас повинен бути індекс у полі іноземного ключа, ви можете просто створити простий індекс у полі "AID"

CREATE INDEX aid_index ON mytable (AID);

і лише потім опускайте унікальний індекс "AID"

ALTER TABLE mytable DROP INDEX AID;

7

Для зовнішнього ключа завжди потрібен індекс. Без індексу, що примушує обмеження, потрібне повне сканування таблиці на посилальній таблиці для кожного вставленого або оновленого ключа в таблиці посилань. І це матиме неприйнятний вплив на продуктивність. Це має два наступні наслідки:

  • Створюючи іноземний ключ, база даних перевіряє, чи існує індекс. Якщо не буде створений індекс За замовчуванням він матиме те саме ім'я, що і обмеження.
  • Якщо є лише один індекс, який може бути використаний для зовнішнього ключа, він не може бути скинутий. Якщо ви дійсно не хочете його скинути, вам або доведеться скинути обмеження зовнішнього ключа або спершу створити інший індекс для нього.

1
у вас є теорія, що інших відповідей бракувало.
Денніс

1
Отже: Якщо у вас є складний унікальний індекс (кілька стовпців з унікальним обмеженням), ви не можете видалити унікальний ключ AB, якщо у вас немає індексу для A і B. Якщо ви отримаєте цю помилку, інша таблиця використовує індекс стовпця A або B, і вам доведеться додати ці, перш ніж ви зможете безпечно видалити унікальний AB.
Робін Де

@RobinDeSchepper Добре зауваження. І при використанні складних унікальних індексів порядок полів не важливий для унікального індексу, але він може бути важливим для зовнішнього ключа. Унікальний індекс на A, B може використовуватися зовнішнім ключем на A, але не зовнішнім ключем на B.
Stefan Mondelaers

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.