#1071 - المفتاح المحدد كانت طويلة جدا ؛ ماكس طول المفتاح هو 767 بايت

StackOverflow https://stackoverflow.com/questions/1814532

سؤال

عندما كنت تنفيذ الأمر التالي:

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

لدي رسالة الخطأ هذه:

#1071 - Specified key was too long; max key length is 767 bytes

معلومات عن column1 و column2:

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

أعتقد varchar(20) يتطلب فقط 21 بايت بينما varchar(500) فقط يتطلب 501 بايت.وبالتالي فإن إجمالي بايت 522 أقل من 767.لماذا أحصل على رسالة الخطأ?

#1071 - Specified key was too long; max key length is 767 bytes
هل كانت مفيدة؟

المحلول

767 بايت هو ذكر بادئة الحد للحصول على الجداول ك InnoDB في الخلية نسخة 5.6 (والإصدارات السابقة). انها 1000 بايت للجداول MYISAM. في الخلية قد زادت الإصدار 5.7 وما فوق هذا الحد إلى 3072 بايت.

لديك أيضا أن يكون على علم أنه إذا قمت بتعيين فهرس على شار أو VARCHAR المجال كبيرة والتي هي utf8mb4 المشفرة، لديك لتقسيم الأقصى طول مؤشر بادئة من 767 بايت (أو 3072 بايت) بنسبة 4 مما أدى إلى 191. وذلك لأن الحد الأقصى لطول حرف utf8mb4 أربعة بايت. لحرف UTF8 سيكون ثلاثة بايت مما أدى إلى أقصى طول مؤشر بادئة من 254.

وخيار واحد لديك هو وضع فقط الحد الأدنى على حقول VARCHAR الخاص بك.

وثمة خيار آخر (وفقا لاستجابة rel="noreferrer"> ) هو الحصول على مجموعة فرعية من العمود بدلا من كامل المبلغ، أي:

ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );

والقرص كما تحتاج إلى الحصول على مفتاح لتطبيق، لكنني أتساءل عما إذا كان سوف يكون من المفيد مراجعة نموذج البيانات الخاص بشأن هذا الكيان لمعرفة ما إذا كان هناك التحسينات التي من شأنها أن تسمح لك لتنفيذ قواعد العمل المقصود دون ضرب الخلية القيد.

نصائح أخرى

إذا كان هناك من وجود مشاكل مع ك InnoDB / UTF-8 تحاول وضع مؤشر UNIQUE في حقل VARCHAR(256)، والتحول إلى VARCHAR(255). يبدو 255 هو الحد.

عندما ضرب الحد.تعيين التالية.

  • ك INNODB utf8 VARCHAR(255)
  • ك INNODB utf8mb4 VARCHAR(191)
يفترض

والخلية أسوأ الحالات لعدد من وحدات البايت لكل حرف في السلسلة. لترميز الخلية "UTF8"، وهذا هو 3 بايت لكل حرف منذ ذلك الترميز لا يسمح الأحرف خارج U+FFFF. لترميز الخلية "utf8mb4، فإنه من 4 بايت لكل حرف، لأن هذا هو ما يدعو الخلية UTF-8 الفعلي.

وحتى على افتراض كنت تستخدم 'UTF8، والعمود الأول تأخذ 60 بايت للمؤشر، والخاص الثاني 1500 آخر.

وتشغيل هذا الاستعلام قبل الاستعلام الخاص بك:

SET @@global.innodb_large_prefix = 1;

وهذا سيزيد حد ل3072 bytes.

وماذا ترميز الأحرف الذي تستخدمه؟ بعض مجموعات الأحرف (مثل UTF-16، وهلم جرا) استخدام أكثر من بايت واحد لكل حرف.

حل Laravel إطار

كما في Laravel 5.4.* الوثائق;لديك لتعيين الافتراضي طول السلسلة داخل boot طريقة app/Providers/AppServiceProvider.php الملف كما يلي:

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

تفسير من هذا الإصلاح ، Laravel 5.4.* الوثائق:

Laravel يستخدم utf8mb4 مجموعة الأحرف الافتراضية التي تشمل دعم لتخزين "emojis" في قاعدة البيانات.إذا كنت تقوم بتشغيل نسخة من الخلية أكبر من 5.7.7 الإفراج أو MariaDB أقدم من الإصدار 10.2.2, قد تحتاج إلى تكوين يدويا الافتراضي طول السلسلة التي تم إنشاؤها بواسطة الهجرات من أجل الخلية إلى إنشاء فهارس بالنسبة لهم.يمكنك تكوين هذا عن طريق الاتصال Schema::defaultStringLength طريقة داخل AppServiceProvider.

بدلا من ذلك, يمكنك تمكين innodb_large_prefix الخيار الخاص بك قاعدة البيانات.الرجوع إلى قاعدة البيانات الخاصة بك للحصول على إرشادات حول كيفية تمكين هذا الخيار.

أعتقد varchar(20) يتطلب فقط 21 بايت بينما varchar(500) فقط يتطلب 501 بايت.وبالتالي فإن إجمالي بايت 522 أقل من 767.فلماذا لم أحصل على رسالة الخطأ?

UTF8 يتطلب 3 بايت لكل حرف لتخزين السلسلة, لذا في حالتك 20 + 500 حرف = 20*3+500*3 = 1560 بايت وهو أكثر من سمحت 767 بايت.

حد UTF8 هو 767/3 = 255 حرفا, ، UTF8mb4 الذي يستخدم 4 بايت لكل حرف هو 767/4 = 191 الشخصيات.


هناك نوعان من الحلول لهذه المشكلة إذا كنت بحاجة إلى استخدام أطول عمود من الحد:

  1. استخدام "أرخص" ترميز (الذي يتطلب أقل بايت لكل حرف)
    في حالتي أنا في حاجة إلى إضافة فهرس فريد على عمود يحتوي على كبار المسئولين الاقتصاديين سلسلة من المادة ، كما تستخدم فقط [A-z0-9\-] شخصيات كبار المسئولين الاقتصاديين ، كنت latin1_general_ci والذي يستخدم بايت واحد فقط لكل حرف و حتى عمود يمكن أن يكون 767 بايت طول.
  2. إنشاء تجزئة من العمود الخاص بك و استخدام فريدة من نوعها مؤشر فقط على أن
    الخيار الآخر بالنسبة لي لإنشاء عمود آخر الذي من شأنه أن متجر تجزئة من كبار المسئولين الاقتصاديين ، هذا العمود قد UNIQUE الرئيسية لضمان SEO القيم هي فريدة من نوعها.أود أن أضيف أيضا KEY مؤشر الأصلية كبار المسئولين الاقتصاديين عمود لتسريع البحث عنها.

الجواب عن لماذا يمكنك الحصول على رسالة الخطأ وقد أجبت من قبل العديد من المستخدمين هنا.جوابي هو حول كيفية إصلاح واستخدامها كما ينبغي.

الرجوع من هذا الرابط.

  1. فتح الخلية العميل (أو MariaDB العميل).بل هو أداة سطر الأوامر.
  2. سوف يطلب كلمة المرور الخاصة بك, أدخل كلمة المرور الصحيحة.
  3. حدد قاعدة البيانات الخاصة بك باستخدام هذا الأمر use my_database_name;

تغيير قاعدة البيانات

  1. set global innodb_large_prefix=on;

سؤال موافق, 0 الصفوف المتأثرة (0.00 ثانية)

  1. set global innodb_file_format=Barracuda;

سؤال موافق, 0 الصفوف المتأثرة (0.02 ثانية)

  1. اذهب إلى قاعدة البيانات الخاصة بك على phpMyAdmin أو شيء من هذا القبيل لسهولة الإدارة.> حدد قاعدة البيانات > عرض الجدول هيكل > انتقل إلى العمليات من علامة التبويب.> تغيير ROW_FORMAT إلى ديناميكية و حفظ التغييرات.
  2. انتقل إلى الجدول هيكل علامة التبويب > انقر على فريدة من نوعها زر.
  3. القيام به.الآن يجب أن لا أخطاء.

المشكلة من هذا الإصلاح هو في حالة تصدير db إلى ملقم آخر (على سبيل المثال من المضيف المحلي الحقيقي المضيف) ولا يمكنك استخدام الخلية سطر الأوامر في ذلك الملقم.لا يمكنك أن تجعل من العمل هناك.

Specified key was too long; max key length is 767 bytes

هل حصلت على تلك الرسالة ل1 بايت يساوي 1 شخصية فقط إذا كنت تستخدم مجموعة أحرف latin-1. إذا كنت تستخدم utf8، وسوف ينظر كل حرف 3 بايت عند تحديد عمود المفتاح الخاص بك. إذا كنت تستخدم utf8mb4، سيتم النظر في كل حرف لتكون 4 بايت عند تحديد عمود المفتاح الخاص بك. وبالتالي، تحتاج إلى مضاعفة عدد الأحرف المسموح حقل المفتاح الخاص بك عن طريق، 1، 3، أو 4 (في بلدي على سبيل المثال) لتحديد عدد وحدات البايت حقل المفتاح هو محاولة للسماح. إذا كنت تستخدم uft8mb4، يمكنك تحديد فقط 191 حرفا لالأصلي، ك InnoDB، حقل المفتاح الأساسي. فقط لا اختراق 767 بايت.

ويمكنك إضافة عمود من MD5 الأعمدة طويلة

واجهنا هذه المشكلة عند محاولة إضافة فهرس فريد إلى حقل VARCHAR (255) باستخدام utf8mb4. بينما حددت المشكلة بشكل جيد هنا بالفعل، وأنا أريد أن أضيف بعض النصائح العملية لكيفية برزت لنا ذلك وحلها.

عند استخدام utf8mb4 والشخصيات عد إلى 4 بايت، في حين ظل UTF8، استطاعوا إلى 3 بايت. قواعد البيانات ك InnoDB لديها الحد الذي يمكن أن يحتوي على الأرقام القياسية فقط 767 بايت. حتى عند استخدام UTF8، يمكنك تخزين 255 حرفا (767/3 = 255)، ولكن باستخدام utf8mb4، يمكنك تخزين فقط 191 حرفا (767/4 = 191).

وكنت قادرا على الاطلاق لإضافة الأرقام القياسية العادية لحقول VARCHAR(255) باستخدام utf8mb4، ولكن ما يحدث هو يتم اقتطاع حجم مؤشر السوق عند مستوى 191 حرفا تلقائيا - مثل unique_key هنا:

وهذا على ما يرام، لأن الأرقام القياسية العادية تستخدم فقط للمساعدة في الخلية البحث من خلال البيانات الخاصة بك بسرعة أكبر. لا تحتاج إلى فهرسة الحقل بالكامل.

وهكذا، لماذا الخلية اقتطاع المؤشر تلقائيا لمؤشرات العادية، ولكن رمي خطأ واضح عندما تحاول أن تفعل ذلك لالفهارس الفريدة؟ حسنا، لماي لتكون قادرة على معرفة إذا كانت قيمة يتم إدراج أو تحديثها موجود بالفعل، فإنه يحتاج إلى الواقع مؤشر القيمة بالكامل وليس فقط جزءا منه.

وفي نهاية اليوم، إذا كنت تريد أن يكون فهرس فريد على حقل محتويات الحقل يجب أن تنسجم مع مؤشر. لutf8mb4، وهذا يعني تقليل أطوال الحقل VARCHAR الخاص بك إلى 191 حرفا أو أقل. إذا كنت لا تحتاج utf8mb4 لهذا الجدول أو الحقل، يمكنك إسقاط مرة أخرى إلى UTF8 وتكون قادرة على الحفاظ على 255 حقل طول.

وهنا هو جوابي الأصلي:

<اقتباس فقرة>   

وأنا مجرد قطرة قاعدة البيانات وإعادة مثل هذا، وذهب خطأ:

     

وdrop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

ومع ذلك، فإنه لا يعمل لجميع الحالات.

وهو في الواقع مشكلة استخدام الفهارس على أعمدة VARCHAR مع utf8 مجموعة الأحرف (أو utf8mb4)، مع أعمدة VARCHAR التي لديها أكثر من طول معين من الأحرف. في حالة utf8mb4، أن مدة معينة هو 191.

يرجى الرجوع إلى قسم مؤشر طويل في هذه المقالة للحصول على مزيد من المعلومات حول كيفية استخدام المؤشرات طويلة في قاعدة بيانات MySQL: <لأ href = "http://hanoian.com/content/index.php/24-automate-the- تحويل واحد في الخلية قاعدة بيانات حرف-وضع-لutf8mb4 "يختلط =" noreferrer "> http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- مجموعة الأحرف إلى utf8mb4

لقد قمت ببعض البحث على هذا الموضوع أخيرا حصلت على بعض مخصص تغيير

ل MySQL workbench 6.3.7 نسخة رسومية بين المرحلة هو متاح

  1. تبدأ منضدة وحدد اتصال.
  2. انتقل إلى إدارة أو مثيل واختر خيارات الملف.
  3. إذا منضدة أسألك إذن قراءة ملف التكوين ثم تسمح بذلك عن طريق الضغط على OK مرتين.
  4. في مركز مسؤول ملف خيارات نافذة يأتي.
  5. انتقل إلى InnoDB التبويب والتحقق من innodb_large_prefix إذا لم يتم في القسم العام.
  6. مجموعة innodb_default_row_format خيار القيمة الحيوية.

للحصول على إصدارات أدناه 6.3.7 المباشر الخيارات ليست متاحة لذلك تحتاج إلى الذهاب مع موجه الأوامر

  1. بدء تشغيل CMD كمسؤول.
  2. انتقل إلى مدير أين خادم mysql هو تثبيت معظم الحالات في "C:\Program Files\MySQL\MySQL Server 5.7\bin" لذلك الأمر "cd \" "cd Program Files\MySQL\MySQL Server 5.7\bin".
  3. الآن تشغيل الأوامر mysql -u userName -p databasescheema الآن طلب كلمة مرور لكل مستخدم.توفر كلمة المرور والدخول في موجه الخلية.
  4. علينا وضع بعض الإعدادات أدخل الأوامر التالية واحدا تلو الآخر مجموعة العالمي innodb_large_prefix=على ؛ مجموعة العالمي innodb_file_format=باراكودا;مجموعة العالمي innodb_file_per_table=true;
  5. الآن في آخر علينا أن يغير ROW_FORMAT المطلوبة الجدول بشكل افتراضي المدمجة علينا أن مجموعة ديناميكية.
  6. استخدام الأوامر التالية alter table table_name ROW_FORMAT=ديناميكية ؛
  7. به

وأنا ثابت هذه المسألة مع:

varchar(200) 

واستبدالها

varchar(191)

وكل VARCHAR التي لديها أكثر من 200 استبدالها 191 أو مجموعة منها النص.

و5 الحلول:

وكان رفعت الحد في 5.7.7 (MariaDB ل10.2.2؟). ويمكن زيادة مع بعض العمل في 5.6 (10.1).

إذا كنت ضرب الحد بسبب محاولة استخدام CHARACTER SET utf8mb4. ثم نفذ أحد الإجراءات التالية (كل لديه عيب) لتجنب الخطأ:

⚈  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
⚈  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
⚈  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
⚈  Use a "prefix" index -- you lose some of the performance benefits.
⚈  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

- http://mysql.rjweb.org/doc.php/limits# 767_limit_in_innodb_indexes

تغيير الترتيب الخاص.يمكنك استخدام utf8_general_ci يدعم تقريبا جميع

ومجرد تغيير utf8mb4 إلى utf8 عندما تحل إنشاء الجداول مشكلتي. على سبيل المثال: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; إلى CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

بالنسبة laravel أو 5.6 5.7 5.8

الخطوات المتبعة

  1. انتقل إلى App\Providers\AppServiceProvider.php.
  2. هذا إضافة إلى المزود use Illuminate\Support\Facades\Schema; في الأعلى.
  3. داخل الحذاء وظيفة إضافة هذا Schema::defaultStringLength(191);

أن كل الاستمتاع.

استنادا إلى العمود أدناه ، أولئك 2 متغير سلسلة أعمدة تستخدم utf8_general_ci جمع (utf8 محارف ضمنية).

في الخلية ، utf8 محارف يستخدم كحد أقصى 3 بايت لكل حرف.وبهذا سوف تحتاج إلى تخصيص 500*3=1500 بايت, والذي هو أكبر بكثير من 767 بايت الخلية يسمح.هذا هو السبب في أنك تحصل على هذا 1071 خطأ.

وبعبارة أخرى, تحتاج إلى حساب عدد الأحرف استنادا إلى محارف بايت التمثيل وليس كل محارف هو بايت واحد تمثيل (كما يفترض.) I. E. utf8 في الخلية هو يستخدم في أكثر من 3 بايت لكل حرف ، 767/3≈255 حرفا ، utf8mb4, وهو على الأكثر 4 بايت التمثيل ، 767/4≈191 الشخصيات.

من المعروف أن الخلية

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

ولقد وجدت هذا الاستعلام مفيدا في كشف الذي كان الأعمدة مؤشر انتهاك الطول الاقصى:

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')

يرجى معرفة ما اذا كان sql_mode مثل

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

وإذا كان التغيير إلى

sql_mode=NO_ENGINE_SUBSTITUTION

وOR

وإعادة تشغيل الملقم تغيير ملف my.cnf الخاص بك (وضع التالية)

innodb_large_prefix=on

في حالتي، كان لي هذه المشكلة عندما كنت النسخ الاحتياطي قاعدة بيانات باستخدام لينكس إعادة توجيه أحرف الإخراج / الإدخال. لذلك، يمكنني تغيير بناء الجملة كما هو موضح أدناه. PS: استخدام لينكس أو ماك محطة

والنسخ الاحتياطي (بدون إعادة توجيه>)

# mysqldump -u root -p databasename -r bkp.sql

واستعادة (بدون <إعادة توجيه)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

و"كان مفتاح محدد طويل جدا؛ أقصى طول المفتاح هو 767 بايت" خطأ بسيط المفقودين

.

فهرس الأطوال & MySQL / MariaDB


Laravel يستخدم utf8mb4 حرف تعيين افتراضيا ، والذي يتضمن دعم لتخزين "emojis" في قاعدة البيانات.إذا كنت تقوم بتشغيل نسخة من الخلية أكبر من 5.7.7 الإفراج أو MariaDB أقدم من الإصدار 10.2.2, قد تحتاج إلى تكوين يدويا الافتراضي طول السلسلة التي تم إنشاؤها بواسطة الهجرات من أجل الخلية إلى إنشاء فهارس بالنسبة لهم.يمكنك تكوين هذا عن طريق الاتصال المخطط::defaultStringLength طريقة داخل AppServiceProvider:

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

بدلا من ذلك ، قد تمكن innodb_large_prefix خيار قاعدة البيانات الخاصة بك. الرجوع إلى قاعدة البيانات الخاصة بك للحصول على إرشادات حول كيفية تمكين هذا الخيار.

إشارة من مسؤول laravel الوثائق : https://laravel.com/docs/5.7/migrations

تغيير محارف من الحقل مؤشر الشكوى إلى "LATIN1"
أي ALTER TABLE TBL أختر myfield myfield VARCHAR (600) CHARACTER SET LATIN1 DEFAULT NULL؛
LATIN1 يأخذ بايت واحد لحرف واحد بدلا من أربعة

إذا كنت خلق شيء مثل:

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

وينبغي أن يكون شيء من هذا القبيل

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

ولكن تحتاج إلى التحقق من تفرد هذا العمود من التعليمات البرمجية أو إضافة عمود جديد باعتباره MD5 أو SHA1 من عمود varchar

ونظرا لضيق بادئة سوف يحدث هذا الخطأ. 767 بايت هو الحد بادئة المعلن للجداول ك InnoDB في الإصدارات الخلية قبل 5.7. انها 1000 بايت للجداول MYISAM. في الخلية قد زادت الإصدار 5.7 وما فوق هذا الحد إلى 3072 بايت.

وتشغيل ما يلي على الخدمة مما يتيح لك الخطأ يجب حل مشكلتك. هذا لابد من تشغيل في MYSQL CLI.

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

لتحديد ذلك، وهذا يعمل بالنسبة لي مثل السحر.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

إذا قمت بتغيير innodb_log_file_size مؤخرا، في محاولة لاستعادة القيمة السابقة التي عملت.

وبالنسبة لي، فإن مسألة "# 1071 - تم تحديد مفتاح طويلة جدا؛ أقصى طول المفتاح هو 767 بايت" تم حلها بعد تغيير أساسي / مزيج uniquekey عن طريق الحد من حجم عمود من 200

.
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top