MySQL Không thể thả chỉ mục cần thiết trong một ràng buộc khóa ngoại


155

Tôi cần phải THAY THẾ cơ sở dữ liệu hiện tại của mình để thêm một cột. Do đó, tôi cũng muốn cập nhật trường ĐỘC ĐÁO để bao gồm cột mới đó. Tôi đang cố gắng xóa chỉ mục hiện tại nhưng tiếp tục gặp lỗiMySQL 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

Giả sử UNIQUE KEY AIDtrên mytable?
Mike Purcell

Câu trả lời:


228

Bạn phải bỏ chìa khóa nước ngoài. Khóa ngoại trong MySQL tự động tạo một chỉ mục trên bảng (Có một câu hỏi SO về chủ đề này).

ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ; 

12
Bạn có thể muốn thêm lại nó sau khi bỏ chỉ mục: ALTER TABLE mytableADD CONSTRAINT mytable_ibfk_1FOREIGN KEY ( AID) TÀI LIỆU THAM KHẢO mytable_a( ID) TRÊN XÓA CASCADE;
laffuste

8
Điều đó thật tuyệt, nhưng tôi có thể làm gì nếu FOREIGN KEYràng buộc của tôi là ẩn danh?
Pehat

@Pehat kiểm tra câu trả lời của tôi bên dưới stackoverflow.com/a/54145440/2305119
thyzz

1
Lưu ý: khóa ngoại có thể không rõ ràng. Để tìm tất cả các khóa ngoại liên quan đến bảng và cột, bạn có thể sử dụng truy vấn này: dba.stackexchange.com/questions/102371/ Kẻ
charlax

84

Bước 1

Liệt kê khóa ngoại (LƯU Ý rằng nó khác với tên chỉ mục)

SHOW CREATE TABLE  <Table Name>

Kết quả sẽ cho bạn thấy tên khóa ngoại.

Định dạng:

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

Bước 2

Phím thả (nước ngoài / chính / khóa)

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

Bước 3

Thả chỉ số.


18

Nếu bạn có nghĩa là bạn có thể làm điều này:

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.

Nhưng sau đó:

ALTER TABLE mytable
DROP KEY AID ;

đưa ra lỗi.


Bạn có thể bỏ chỉ mục và tạo một chỉ mục mới trong một ALTER TABLEcâu lệnh:

ALTER TABLE mytable
DROP KEY AID ,
ADD UNIQUE KEY AID (AID, BID, CID, DID);

8

Vì bạn phải có một chỉ mục trên trường khóa ngoài, bạn chỉ có thể tạo một chỉ mục đơn giản trên trường 'AID'

CREATE INDEX aid_index ON mytable (AID);

và chỉ sau đó thả chỉ mục duy nhất 'AID'

ALTER TABLE mytable DROP INDEX AID;

7

Khóa ngoại luôn yêu cầu một chỉ mục. Nếu không có chỉ mục thực thi ràng buộc sẽ yêu cầu quét toàn bộ bảng trên bảng được tham chiếu cho mỗi khóa được chèn hoặc cập nhật trong bảng tham chiếu. Và điều đó sẽ có tác động hiệu suất không thể chấp nhận. Điều này có 2 hậu quả sau:

  • Khi tạo khóa ngoại, cơ sở dữ liệu sẽ kiểm tra nếu chỉ mục tồn tại. Nếu không một chỉ mục sẽ được tạo ra. Theo mặc định, nó sẽ có cùng tên với ràng buộc.
  • Khi chỉ có một chỉ mục có thể được sử dụng cho khóa ngoại, nó không thể bị hủy. Nếu bạn thực sự không muốn bỏ nó, bạn phải bỏ ràng buộc khóa ngoại hoặc tạo một chỉ mục khác cho nó trước.

1
bạn có lý thuyết mà các câu trả lời khác thiếu.
Dennis

1
Vì vậy: Nếu bạn có một chỉ mục duy nhất ghép (nhiều cột trong một ràng buộc duy nhất), bạn không thể xóa khóa AB duy nhất trừ khi bạn có một chỉ mục cho A và B. Nếu bạn gặp lỗi này, một bảng khác đang sử dụng chỉ mục của cột A hoặc B, và bạn sẽ phải thêm chúng trước khi bạn có thể xóa AB duy nhất một cách an toàn.
Robin De Schepper

@RobinDeSchepper Nhận xét tốt. Và khi sử dụng các chỉ mục duy nhất ghép, thứ tự của các trường không quan trọng đối với chỉ mục duy nhất, nhưng nó có thể quan trọng đối với khóa ngoại. Một chỉ số duy nhất trên A, B có thể được sử dụng bởi khóa ngoại trên A, nhưng không phải bởi khóa ngoại trên B.
Stefan Mondelaers

2

Tôi nghĩ rằng đây là cách dễ dàng để giảm chỉ số.

set FOREIGN_KEY_CHECKS=1;

ALTER TABLE mytable DROP INDEX AID;

set FOREIGN_KEY_CHECKS=0;

2
Tôi nghĩ rằng bạn đã trao đổi kích hoạt và vô hiệu hóa kiểm tra. Ở đầu tôi sẽ mong đợi FOREIGN_KEY_CHEK=0và ở cuối FOREIGN_KEY_CHEK=1.
lãng mạn

0

Trong trường hợp của tôi, tôi đã đánh rơi khóa ngoại và tôi vẫn không thể bỏ chỉ mục. Đó là bởi vì có một bảng khác có khóa ngoại đối với bảng này trên cùng các trường. Sau khi tôi đánh rơi khóa ngoại trên bảng khác, tôi có thể bỏ các chỉ mục trên bảng này.


0

Nếu bạn muốn thả cột Khóa ngoại (phù thủy giữ một ràng buộc), bạn nên bỏ khóa ngoại trước rồi thả cột, khi bạn thả khóa ngoại, bạn không phải chuyển tất cả tên, chỉ cần chuyển khóa Ngoại tên cột dọc:

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

biết thêm chi tiết về:

https://laravel.com/docs/6.x/migations#forign-key-constraint

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.