2011-11-08 32 views
47

Tôi đang cố gắng loại bỏ các bản sao từ một bảng MySQL bằng cách sử dụng ALTER IGNORE TABLE + một phím UNIQUE. Tài liệu MySQL cho biết:MySQL: ALTER IGNORE TABLE cho "Vi phạm ràng buộc toàn vẹn"

IGNORE là một phần mở rộng của MySQL cho SQL chuẩn. Nó kiểm soát cách ALTER TABLE hoạt động nếu có bản sao trên các khóa duy nhất trong bảng mới hoặc nếu cảnh báo xảy ra khi chế độ nghiêm ngặt được bật. Nếu IGNORE không được chỉ định, bản sao sẽ bị hủy bỏ và được khôi phục nếu xảy ra lỗi trùng lặp. Nếu IGNORE được chỉ định, chỉ hàng đầu tiên được sử dụng các hàng có các bản sao trên một khóa duy nhất. Các hàng xung đột khác sẽ bị xóa. Các giá trị không đúng được cắt ngắn thành giá trị chấp nhận được gần nhất.

Khi tôi chạy truy vấn ...

ALTER IGNORE TABLE table ADD UNIQUE INDEX dupidx (field) 

... Tôi vẫn nhận được lỗi # 1062 - Duplicate entry 'blabla' cho khóa 'dupidx'.

Trả lời

95

Mở rộng từ khóa IGNORE thành MySQL dường như có một số bug in the InnoDB version trên một số phiên bản của MySQL.

Bạn luôn có thể, chuyển đổi sang MyISAM, BỎ QUA-ADD chỉ mục và sau đó chuyển đổi trở lại InnoDB

ALTER TABLE table ENGINE MyISAM; 
ALTER IGNORE TABLE table ADD UNIQUE INDEX dupidx (field); 
ALTER TABLE table ENGINE InnoDB; 

Lưu ý, nếu bạn có ràng buộc khoá ngoại này sẽ không làm việc, bạn sẽ phải gỡ bỏ những đầu tiên và thêm lại sau.

+56

Trong đó liên kết đến lỗi InnoDB có một cách giải quyết đề nghị để chạy đầu tiên 'thiết lập phiên old_alter_table = 1; 'này làm việc cho! tôi. – Peter

+1

Cảm ơn Peter - điều này dường như đang làm việc cho tôi bây giờ. Không có ý tưởng về vấn đề này - máy dev của tôi là mariadb nhưng khi tôi đã phải chạy trên sản xuất (mysql 5.5) chạy vào này. Stackoverflow này đã lưu lại ngày của tôi! – spidie

+5

Đây có thể là câu trả lời tồi tệ nhất mà tôi từng thấy trên Stack Overflow. Thay đổi công cụ lưu trữ là một cam kết đáng kể trong chính nó với các bảng có kích thước trung bình. Ba truy vấn này có khả năng có thể khóa máy chủ cơ sở dữ liệu trong nhiều giờ. Đây không phải là một giải pháp. – Mikkel

2

Sự cố là bạn có dữ liệu trùng lặp trong trường mà bạn đang cố lập chỉ mục. Bạn sẽ cần xóa các bản sao vi phạm trước khi bạn có thể thêm một chỉ mục duy nhất.

Một cách là phải làm như sau:

CREATE TABLE tmp_table LIKE table; 
    ALTER IGNORE TABLE tmp_table ADD UNIQUE INDEX dupidx (field); 
    INSERT IGNORE INTO tmp_table SELECT * FROM table; 
    DROP TABLE table; 
    RENAME TABLE tmp_table TO table; 

này cho phép bạn chèn chỉ có dữ liệu độc đáo vào bảng

+0

Không, từ khóa IGNORE nên chăm sóc những bản sao đó. Đó sẽ là vẻ đẹp của giải pháp này. Xem tài liệu được trích dẫn trong câu hỏi của tôi. –

25

Hoặc thử thiết lập phiên old_alter_table = 1 (Đừng quên để thiết lập nó lại)

Xem: http://mysqlolyk.wordpress.com/2012/02/18/alter-ignore-table-add-index-always-give-errors/

+2

Điều này đã làm việc cho tôi. Nó dài trên bảng lớn, nhưng nó có vẻ khá tuyến tính. Trên máy tính của tôi, nó có thể xử lý khoảng 2GiB dữ liệu mỗi giờ, khoảng hai ngày. Tôi tự hỏi làm thế nào mà so sánh với các giải pháp được chấp nhận, đó là để chuyển đổi sang myISAM, thêm chỉ mục và chuyển đổi trở lại. –

+0

Hãy coi chừng! Nếu bạn đang sử dụng bản sao, cài đặt 'old_alter_table' sẽ không tái tạo, vì vậy' ALTER TABLE IGNORE' sẽ không thành công trên slave và nhân rộng.Để sửa lỗi này, tôi đã thực hiện 'ALTER' theo cách thủ công trên slave, sau đó bỏ qua' ALTER TABLE 'vi phạm bằng cách sử dụng 'SET GLOBAL sql_slave_skip_counter = 1', sau đó tiếp tục sao chép. – thenickdude

Các vấn đề liên quan