2012-01-05 43 views
47

Tôi biết câu hỏi với tiêu đề này đã được trả lời trước đây, nhưng hãy đọc tiếp. Tôi đã đọc kỹ tất cả các câu hỏi/câu trả lời khác về lỗi này trước khi đăng.# 1071 - Khóa được chỉ định quá dài; độ dài khóa tối đa là 1000 byte

Tôi nhận được báo lỗi trên cho truy vấn sau đây:

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
    `menu_id` varchar(32) NOT NULL, 
    `parent_menu_id` int(32) unsigned DEFAULT NULL, 
    `menu_name` varchar(255) DEFAULT NULL, 
    `menu_link` varchar(255) DEFAULT NULL, 
    `plugin` varchar(255) DEFAULT NULL, 
    `menu_type` int(1) DEFAULT NULL, 
    `extend` varchar(255) DEFAULT NULL, 
    `new_window` int(1) DEFAULT NULL, 
    `rank` int(100) DEFAULT NULL, 
    `hide` int(1) DEFAULT NULL, 
    `template_id` int(32) unsigned DEFAULT NULL, 
    `alias` varchar(255) DEFAULT NULL, 
    `layout` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`menu_id`), 
    KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

Có ai có ý tưởng tại sao và làm thế nào để sửa chữa nó? Bắt là - cùng một truy vấn này hoạt động hoàn hảo trên máy cục bộ của tôi, và làm việc tốt trên máy chủ cũ của tôi. Btw.it từ một dự án trưởng thành - phpdevshell - vì vậy tôi đoán những người này biết họ đang làm gì, mặc dù bạn không bao giờ biết.

Bất kỳ đầu mối nào được đánh giá cao.

Tôi đang sử dụng phpMyAdmin.

Trả lời

94

Như @Devart cho biết, tổng thời lượng chỉ mục của bạn quá dài.

Câu trả lời ngắn gọn là bạn không nên lập chỉ mục các cột VARCHAR dài như vậy, vì chỉ mục sẽ rất cồng kềnh và không hiệu quả.

Cách tốt nhất là sử dụng chỉ mục tiền tố để bạn chỉ lập chỉ mục chuỗi con bên trái của dữ liệu. Hầu hết dữ liệu của bạn sẽ ngắn hơn rất nhiều so với 255 ký tự.

Bạn có thể khai báo độ dài tiền tố cho mỗi cột khi bạn xác định chỉ mục. Ví dụ:

... 
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50)) 
... 

Nhưng độ dài tiền tố tốt nhất cho một cột nhất định là bao nhiêu? Dưới đây là một phương pháp để tìm hiểu:

SELECT 
ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(*),2) AS pct_length_10, 
ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(*),2) AS pct_length_20, 
ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(*),2) AS pct_length_50, 
ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(*),2) AS pct_length_100 
FROM `pds_core_menu_items`; 

Nó cho bạn biết tỷ lệ hàng không có độ dài chuỗi nhất định trong cột menu_link. Bạn có thể thấy kết quả như sau:

+---------------+---------------+---------------+----------------+ 
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 | 
+---------------+---------------+---------------+----------------+ 
|   21.78 |   80.20 |  100.00 |   100.00 | 
+---------------+---------------+---------------+----------------+ 

Điều này cho bạn biết rằng 80% chuỗi của bạn có ít hơn 20 ký tự và tất cả các chuỗi của bạn dưới 50 ký tự. Vì vậy, không cần phải lập chỉ mục nhiều hơn độ dài tiền tố là 50 và chắc chắn không cần lập chỉ mục toàn bộ độ dài 255 ký tự.

PS: Các loại dữ liệu INT(1)INT(32) chỉ ra một sự hiểu lầm khác về MySQL. Đối số dạng số không có hiệu lực liên quan đến bộ nhớ hoặc phạm vi giá trị được phép cho cột.INT luôn là 4 byte và luôn cho phép các giá trị từ -2147483648 đến 2147483647. Đối số dạng số về giá trị đệm trong khi hiển thị, không có hiệu lực trừ khi bạn sử dụng tùy chọn ZEROFILL.

+6

Cảm ơn rất nhiều vì đã giải thích chi tiết. Ngoài việc sửa chữa một vấn đề, tôi cũng đã học được điều gì đó có giá trị. – CodeVirtuoso

+1

Đó là một truy vấn gọn gàng, cảm ơn bạn đã chia sẻ! – yekta

+0

Truy vấn thực sự, rất hữu ích để tìm ra độ dài mà chỉ mục sẽ được đặt. Đã sử dụng điều này một số lần để xác định độ dài tốt nhất cho một chỉ mục. Cảm ơn bạn đã chia sẻ! –

17

Lỗi này có nghĩa là độ dài của chỉ mục index là hơn 1000 byte. MySQL và các công cụ lưu trữ có thể có hạn chế này. Tôi có lỗi tương tự trên MySQL 5.5 - 'Khóa được chỉ định quá dài; độ dài khóa tối đa là 3072 byte 'khi chạy tập lệnh này:

CREATE TABLE IF NOT EXISTS test_table1 (
    column1 varchar(500) NOT NULL, 
    column2 varchar(500) NOT NULL, 
    column3 varchar(500) NOT NULL, 
    column4 varchar(500) NOT NULL, 
    column5 varchar(500) NOT NULL, 
    column6 varchar(500) NOT NULL, 
    KEY `index` (column1, column2, column3, column4, column5, column6) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

UTF8 là nhiều byte và độ dài khóa được tính theo cách này - 500 * 3 * 6 = 9000 byte.

Nhưng lưu ý, truy vấn tiếp theo hoạt động!

CREATE TABLE IF NOT EXISTS test_table1 (
    column1 varchar(500) NOT NULL, 
    column2 varchar(500) NOT NULL, 
    column3 varchar(500) NOT NULL, 
    column4 varchar(500) NOT NULL, 
    column5 varchar(500) NOT NULL, 
    column6 varchar(500) NOT NULL, 
    KEY `index` (column1, column2, column3, column4, column5, column6) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

... vì tôi đã sử dụng CHARSET = latin1, trong trường hợp này chiều dài khóa là 500 * 6 = 3000 byte.

+4

Cảm ơn bạn đã trả lời, tính năng này hoạt động nhưng với chi phí từ bỏ bộ ký tự utf8. Có thể hạn chế này bằng cách nào đó được khắc phục (tôi có quyền truy cập máy chủ đầy đủ), có phải vì lý do chính đáng không? – CodeVirtuoso

2

Giới hạn kích thước chỉ mục này dường như lớn hơn đối với các bản dựng MySQL 64 bit.

Tôi đã đạt đến giới hạn này khi cố gắng đổ cơ sở dữ liệu dev của chúng tôi và tải nó lên máy ảo VMWare cục bộ. Cuối cùng tôi nhận ra rằng máy chủ dev từ xa là 64 bit và tôi đã tạo ra một đức tính 32 bit. Tôi vừa tạo ra một bản 64 bit và tôi có thể tải cơ sở dữ liệu cục bộ.

5

chạy truy vấn này trước khi tạo hoặc thay đổi bảng.

SET @@global.innodb_large_prefix = 1;

này sẽ đặt dài khóa tối đa đến 3072 byte

1

Tôi đã chỉ cần thực hiện bypass lỗi này bằng cách chỉ cần thay đổi các giá trị của "chiều dài" trong cơ sở dữ liệu ban đầu với tổng số khoảng "1000 "bằng cách thay đổi cấu trúc của nó, và sau đó xuất khẩu cùng, đến máy chủ. :)

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