django.db.utils.OperationalError: (1071, «Указанный ключ слишком длинный; максимальная длина ключа — 767 байт»)

Моя модель:

class Course(models.Model):
    language = models.ForeignKey(Language)
    name = models.CharField(max_length=50, unique=True, default='course')
    title = models.CharField(max_length=1024, default='no title')
    foreign_title = models.CharField(max_length=1024, default='no title', blank=True)
    header = models.CharField(max_length=1024, default='', blank=True)
    description = models.TextField(null=True, blank=True)

    def __str__(self):
        return self.title

    def __unicode__(self):
        return u'%s' % self.title

Я добавляю "unique_together":

class Course(models.Model):
    language = models.ForeignKey(Language)
    name = models.CharField(max_length=50, unique=True, default='course')
    title = models.CharField(max_length=1024, default='no title')
    foreign_title = models.CharField(max_length=1024, default='no title', blank=True)
    header = models.CharField(max_length=1024, default='', blank=True)
    description = models.TextField(null=True, blank=True)

    class Meta:
        unique_together = ['language', 'name', 'title']

    def __str__(self):
        return self.title

    def __unicode__(self):
        return u'%s' % self.title

Время миграции с ошибкой:

 django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')

Моя БД: mysql Ver 15.1 Distrib 10.0.17-MariaDB, для debian-linux-gnu (x86_64) с использованием readline 5.2

Я попытался увеличить длину индекса mysql:

MariaDB [(none)]> set global innodb_file_format = BARRACUDA;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> set global innodb_large_prefix = ON;
Query OK, 0 rows affected (0.00 sec)

Но этого еще недостаточно:

django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 3072 bytes')

Длина индекса проблемы. Как указать ограничение длины индекса Django?


person Stan Zeez    schedule 21.04.2015    source источник
comment
Я ограничил себя: unique_together = ['language', 'name'] (работает), но хотелось бы иметь: unique_together = ['language', 'name', 'title']   -  person Stan Zeez    schedule 22.04.2015


Ответы (8)


решение

ALTER DATABASE `databasename` CHARACTER SET utf8; 
person Giuseppe De Marco    schedule 12.04.2017
comment
Я также должен отметить, что utf8 поддерживает только 3 байта на символ! См. здесь: medium.com/@adamhooper/< /а> - person bparker; 05.07.2018

Вы можете снова воссоздать «базу данных»:

CREATE DATABASE mydatabase CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

или изменить файл конфигурации. Откройте /etc/mysql/mariadb.conf.d/50-server.cnf и измените:

character-set-server  = utf8
collation-server      = utf8_general_ci
person Ivan Kukurudziak    schedule 12.03.2018

Предыдущие два ответа не помогли в моем случае, поэтому я публикую свое решение для моего случая, когда ваш предел равен 1000 (т.е. 1071, «Указанный ключ был слишком длинным; максимальная длина ключа составляет 1000 байтов»).

Прежде всего, убедитесь, что вы работаете с кодировкой utf8!

Затем перейдите к файлу настроек my.ini, найдите строку default-storage-engine=xxx. Если это

default-storage-engine=MYISAM

пожалуйста, измените на

default-storage-engine=InnoDB

Тогда проблема должна быть решена.

Причина в том, что MYISAM не поддерживает размер ключа более 1000 байт.

person MewX    schedule 25.11.2017

Я думаю, что все 4 из этих вещей необходимы:

SET GLOBAL innodb_file_per_table = ON,
           innodb_file_format = Barracuda,
           innodb_large_prefix = ON;
CREATE/ALTER TABLE ...
    ROW_FORMAT = DYNAMIC or COMPRESSED

Это должно превысить ограничение в 767 байтов для одного столбца, но не превысит ограничение в 3072 байта для всего индекса.

Чтобы получить составной уникальный индекс, состоящий из строк, нормализуйте некоторые строки. Замена длинной строки 4-байтовым INT приведет к уменьшению индекса ниже предела.

person Rick James    schedule 21.04.2015
comment
Не помогло. В любом случае: django.db.utils.OperationalError: (1071, «Указанный ключ слишком длинный; максимальная длина ключа — 3072 байта»). - person Stan Zeez; 22.04.2015
comment
@StanZeez - Мой ответ был написан 5 лет назад. Вот что может быть обновлением: mysql.rjweb.org/doc.php/limits# 767_limit_in_innodb_indexes - person Rick James; 05.03.2021

Просто обновите и перенесите базу данных на MySQL-8.0.11 или ** MySQL-5.7.21**, также обязательно используйте utf8 и utf8_general_ci

У меня была эта проблема, затем я обновился до 8.0.11 в тестовой среде и до 5.7.21 на сервере. Теперь он мигрирует в обе среды.

person Julian Maya    schedule 12.07.2018

Обновите mysql до версии 5.7 и повторите попытку миграции.

wget https://dev.mysql.com/get/mysql-apt-config_0.8.1-1_all.deb  
sudo dpkg -i mysql-apt-config_0.8.1-1_all.deb  
sudo apt-get update
sudo apt-get install mysql-server
person 官智鹏    schedule 30.07.2018

в итоге я добавил

'OPTIONS': { 'init_command': 'SET storage_engine=INNODB;' }

к моей конфигурации, поддерживаемой БД, в settings.py, и это устранило проблему.

Сервер MySQL был настроен на использование InnoDB в качестве механизма по умолчанию, но по какой-то причине он все еще пытался создавать таблицы с помощью MyISAM. Я использую MySQL 5.1 с Django 2.2.1 и Python 3.6.7.

person tstoev    schedule 19.05.2019

Поскольку это один из лучших постов для такого рода ошибок, я могу поделиться своим решением, которое сработало для меня при сохранении путей S3 в мою базу данных.

Я добавляю индекс MySQL prefix в нужное поле.

# my_app/models.py
class File(models.Model):
    s3_path = models.CharField(max_length=1024, help_text="S3 object key")


# my_app/migration_000x.py
from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
        (...),
    ]

    operations = [
        migrations.RunSQL(
            sql="CREATE INDEX my_app_file_s3_path__prefix ON my_app_file (s3_path(768));",
            reverse_sql="DROP INDEX my_app_file_s3_path__prefix ON my_app_file;",
        )
    ]

Мне это сойдет с рук, потому что я знаю, что большинство записей будут довольно короткими (100-200 символов), поэтому они выиграют даже от простого индекса префикса, но я все еще поддерживаю max_length, который навязан мне AWS S3.

Я использую движок InnoDB с utf8mb4_unicode_ci для всех своих таблиц.

person mislavcimpersak    schedule 06.04.2021