# 1071 - คีย์ที่ระบุยาวเกินไป ความยาวคีย์สูงสุดคือ 1,000 ไบต์


106

ฉันรู้ว่าคำถามที่มีชื่อนี้ได้รับคำตอบมาก่อนแล้ว แต่โปรดอ่านต่อ ฉันได้อ่านคำถาม / คำตอบอื่น ๆ เกี่ยวกับข้อผิดพลาดนี้อย่างละเอียดก่อนโพสต์

ฉันได้รับข้อผิดพลาดข้างต้นสำหรับข้อความค้นหาต่อไปนี้:

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;

ใครมีความคิดว่าทำไมและวิธีแก้ไข? สิ่งที่จับได้คือ - ข้อความค้นหาเดียวกันนี้ทำงานได้อย่างสมบูรณ์บนเครื่องในพื้นที่ของฉันและทำงานได้ดีกับโฮสต์ก่อนหน้าของฉัน มันมาจากโปรเจ็กต์สำหรับผู้ใหญ่ - phpdevshell - ดังนั้นฉันเดาว่าพวกนี้รู้ว่าพวกเขากำลังทำอะไรแม้ว่าคุณจะไม่เคยรู้

เบาะแสใด ๆ ที่ชื่นชม

ฉันใช้ phpMyAdmin

คำตอบ:


175

ดังที่ @Devart กล่าวความยาวรวมของดัชนีของคุณยาวเกินไป

คำตอบสั้น ๆ คือคุณไม่ควรจัดทำดัชนีคอลัมน์ VARCHAR ที่ยาวเช่นนี้เพราะดัชนีจะมีขนาดใหญ่มากและไม่มีประสิทธิภาพ

แนวทางปฏิบัติที่ดีที่สุดคือใช้ดัชนีคำนำหน้าดังนั้นคุณจึงจัดทำดัชนีสตริงย่อยด้านซ้ายของข้อมูลเท่านั้น ข้อมูลส่วนใหญ่ของคุณจะสั้นกว่า 255 อักขระเป็นอย่างมาก

คุณสามารถประกาศความยาวของคำนำหน้าต่อคอลัมน์เมื่อคุณกำหนดดัชนี ตัวอย่างเช่น:

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

แต่ความยาวของคำนำหน้าที่ดีที่สุดสำหรับคอลัมน์หนึ่ง ๆ คืออะไร? นี่คือวิธีการค้นหา:

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

จะบอกคุณถึงสัดส่วนของแถวที่มีความยาวสตริงไม่เกินที่กำหนดในmenu_linkคอลัมน์ คุณอาจเห็นผลลัพธ์ดังนี้:

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

สิ่งนี้จะบอกคุณว่า 80% ของสตริงของคุณมีอักขระน้อยกว่า 20 ตัวและสตริงทั้งหมดของคุณมีอักขระน้อยกว่า 50 ตัว ดังนั้นจึงไม่จำเป็นต้องจัดทำดัชนีมากกว่าความยาวคำนำหน้า 50 และไม่จำเป็นต้องสร้างดัชนีความยาวเต็มที่ 255 อักขระ

PS: INT(1)และINT(32)ประเภทข้อมูลบ่งบอกถึงความเข้าใจผิดอื่น ๆ เกี่ยวกับ MySQL อาร์กิวเมนต์ตัวเลขไม่มีผลที่เกี่ยวข้องกับการจัดเก็บหรือช่วงของค่าที่อนุญาตสำหรับคอลัมน์ INTเป็น 4 ไบต์เสมอและอนุญาตให้มีค่าตั้งแต่ -2147483648 ถึง 2147483647 เสมออาร์กิวเมนต์ตัวเลขเกี่ยวกับการเติมค่าระหว่างการแสดงผลซึ่งไม่มีผลใด ๆ เว้นแต่คุณจะใช้ZEROFILLตัวเลือก


17
ขอบคุณมากสำหรับคำอธิบายโดยละเอียด นอกเหนือจากการแก้ไขปัญหาแล้วฉันยังได้เรียนรู้สิ่งที่มีค่าอีกด้วย
CodeVirtuoso

คำค้นหาที่มีประโยชน์มากสำหรับการค้นหาความยาวที่ควรตั้งค่าดัชนี ใช้วิธีนี้ในการกำหนดความยาวที่ดีที่สุดสำหรับดัชนี ขอบคุณสำหรับการแชร์!
Niraj Kumar

1
มีข้อผิดพลาดเล็กน้อยในแบบสอบถามที่ใช้งานง่ายของคุณเพื่อวัดระยะเวลาที่สตริงจริงๆ: คุณกำลังสมมติว่ามีสตริงทั้งหมด นั่นคือพวกเขาทั้งหมดอยู่ที่นั่น หากบางส่วนเป็นโมฆะจะทำให้การคำนวณของคุณไม่สมบูรณ์และรายงานสตริงสั้น ๆ คุณต้องการใช้ count ([field_name]) แทน count (*)
D Mac

จะไม่ใช้มากกว่าดัชนี "คำนำหน้า" แรก
Rick James

28

ข้อผิดพลาดนี้หมายความว่าความยาวของดัชนีindexมากกว่า 1,000 ไบต์ MySQL และเครื่องมือจัดเก็บข้อมูลอาจมีข้อ จำกัด นี้ ฉันมีข้อผิดพลาดที่คล้ายกันใน MySQL 5.5 - 'คีย์ที่ระบุยาวเกินไป ความยาวคีย์สูงสุดคือ 3072 ไบต์ 'เมื่อรันสคริปต์นี้:

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 เป็นแบบหลายไบต์และคำนวณความยาวของคีย์ด้วยวิธีนี้ - 500 * 3 * 6 = 9000 ไบต์

แต่โปรดทราบว่าแบบสอบถามถัดไปใช้ได้ผล!

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;

... เนื่องจากฉันใช้ CHARSET = latin1 ในกรณีนี้ความยาวของคีย์คือ 500 * 6 = 3000 ไบต์


7
ขอบคุณสำหรับการตอบกลับมันใช้งานได้ แต่ต้องเสียค่าใช้จ่ายในการเลิกใช้ชุดอักขระ utf8 สามารถเอาชนะข้อ จำกัด นี้ได้หรือไม่ (ฉันมีสิทธิ์เข้าถึงเซิร์ฟเวอร์เต็มรูปแบบ) มีเหตุผลที่ดีหรือไม่?
CodeVirtuoso

5
นี่เป็นคำแนะนำที่แย่มากโปรดเรียนรู้ว่าชุดอักขระคืออะไรและจะทำให้เกิดปัญหาใหญ่ในอนาคตได้อย่างไร ฐานข้อมูลชุดอักขระแบบผสมไม่เพียง แต่ทำให้เกิดปัญหาเมื่อใช้การรวมหรือการเลือกย่อยเท่านั้น แต่ยังทำให้ข้อมูลของคุณอยู่ในรูปแบบที่ไม่เป็นมาตรฐานและอาจไม่สามารถแก้ไขได้ในภายหลัง
Geoffrey

17

ฉันมีปัญหานี้และแก้ไขได้โดยทำตาม:

สาเหตุ

มีข้อบกพร่องที่ทราบเกี่ยวกับ MySQL ที่เกี่ยวข้องกับ MyISAM ชุดอักขระ UTF8 และดัชนีซึ่งคุณสามารถตรวจสอบได้ที่นี่

ความละเอียด

  • ตรวจสอบให้แน่ใจว่าได้กำหนดค่า MySQL ด้วยกลไกการจัดเก็บ InnoDB

  • เปลี่ยนเครื่องมือจัดเก็บที่ใช้โดยค่าเริ่มต้นเพื่อให้สร้างตารางใหม่ได้อย่างเหมาะสมเสมอ:

    set GLOBAL storage_engine='InnoDb';

  • สำหรับ MySQL 5.6 และใหม่กว่าให้ใช้สิ่งต่อไปนี้:

    SET GLOBAL default_storage_engine = 'InnoDB';

  • และในที่สุดก็ทำให้แน่ใจว่าคุณได้ทำตามคำแนะนำที่ระบุไว้ในการโยกย้ายไปยัง MySQL

ข้อมูลอ้างอิง


ในกรณีส่วนใหญ่เราลืมกำหนดค่าเครื่องมือจัดเก็บข้อมูลเป็น 'InnoDB' คำตอบต่อไปนี้เป็นคำตอบที่ง่ายที่สุดและอาจแก้ปัญหาสำหรับผู้ใช้ส่วนใหญ่ที่นี่ ขอบคุณ.
Frederiko Cesar

10

เรียกใช้แบบสอบถามนี้ก่อนสร้างหรือแก้ไขตาราง

SET @@global.innodb_large_prefix = 1;

จะตั้งค่าความยาวคีย์สูงสุดเป็น 3072 ไบต์


3

ขีด จำกัด ขนาดดัชนีนี้ดูเหมือนจะใหญ่กว่าในรุ่น 64 บิตของ MySQL

ฉันประสบข้อ จำกัด นี้ในการพยายามถ่ายโอนฐานข้อมูล dev ของเราและโหลดลงใน VMWare Virt ในที่สุดฉันก็รู้ว่าเซิร์ฟเวอร์ dev ระยะไกลเป็น 64 บิตและฉันได้สร้างคุณธรรม 32 บิต ฉันเพิ่งสร้างคุณธรรม 64 บิตและฉันสามารถโหลดฐานข้อมูลในเครื่องได้


2

ฉันเพิ่งทำการข้ามข้อผิดพลาดนี้โดยเพียงแค่เปลี่ยนค่าของ "ความยาว" ในฐานข้อมูลเดิมให้เป็นค่าทั้งหมดประมาณ "1,000" โดยเปลี่ยนโครงสร้างจากนั้นส่งออกข้อมูลเดียวกันไปยังเซิร์ฟเวอร์ :)


1

ฉันประสบปัญหาเดียวกันใช้แบบสอบถามด้านล่างเพื่อแก้ไข

ในขณะที่สร้างฐานข้อมูลคุณสามารถใช้การเข้ารหัส utf-8

เช่น. create database my_db character set utf8 collate utf8mb4;

แก้ไข: (พิจารณาข้อเสนอแนะจากความคิดเห็น) เปลี่ยน utf8_bin เป็น utf8mb4


2
สิ่งนี้ชี้ให้ฉันไปในทิศทางที่ถูกต้อง สำหรับฉันฉันต้องเปลี่ยนการเรียงลำดับเป็น: utf8_general_ci
Ian Newland

2
นี่ไม่ใช่ทิศทางที่ถูกต้องอย่าทำเช่นนี้! MySQL utf8ไม่ใช่utf8มันเป็นรูปแบบที่เป็นกรรมสิทธิ์ที่ถูกดักฟังซึ่งไม่ควรเกิดขึ้น utf8mb4เป็นจริงutf8และเป็นค่าเริ่มต้นที่แนะนำสำหรับการutf8สนับสนุนที่เหมาะสม
Geoffrey

utf8mb4เป็นการเข้ารหัสที่ถูกต้องสำหรับใช้กับ mysql ไม่ใช่utf8
alok

มันเป็นเพียงตัวอย่าง - อย่างไรก็ตามฉันได้อัปเดตคำตอบแล้ว
Sudhir Dhumal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.