【问题标题】:django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')django.db.utils.OperationalError: (1071, '指定的密钥太长;最大密钥长度为 767 字节')
【发布时间】:2015-06-29 04:43:41
【问题描述】:

我的模特:

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索引如何指定长度限制?

【问题讨论】:

  • 我限制了自己:unique_together = ['language', 'name'](有效),但我想拥有:unique_together = ['language', 'name', 'title']

标签: python django database mariadb migrate


【解决方案1】:

解决办法

ALTER DATABASE `databasename` CHARACTER SET utf8; 

【讨论】:

【解决方案2】:

您可以再次重新创建“数据库”:

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

【讨论】:

    【解决方案3】:

    前两个答案对我的情况没有帮助,因此当您的限制为 1000 时,我将我的解决方案发布到我的情况(即 1071,“指定的密钥太长;最大密钥长度为 1000 字节”) .

    首先,确保您正在处理utf8 编码!

    然后,导航到您的设置文件my.ini,找到default-storage-engine=xxx 行。如果是

    default-storage-engine=MYISAM
    

    请改成

    default-storage-engine=InnoDB
    

    那么,问题应该解决了。

    原因很简单,因为MYISAM 不支持大于 1000 字节的密钥大小。

    【讨论】:

      【解决方案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 替换长字符串会将索引缩小到限制以下。

      【讨论】:

      【解决方案5】:

      只需将数据库升级并迁移到 MySQL-8.0.11 或 ** MySQL-5.7.21** 并确保使用 utf8utf8_general_ci

      我遇到了这个问题,然后我在测试环境上更新到 8.0.11,在服务器上更新到 5.7.21。现在它可以在两种环境中迁移。

      【讨论】:

        【解决方案6】:

        将 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
        

        【讨论】:

          【解决方案7】:

          我最终添加了

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

          到我在 settings.py 中的数据库支持的配置并解决了问题。

          MySQL 服务器被配置为使用 InnoDB 作为默认引擎,但由于某种原因,它仍然尝试使用 MyISAM 创建表。我正在使用 Django 2.2.1 和 Python 3.6.7 运行 MySQL 5.1

          【讨论】:

            【解决方案8】:

            由于这是此类错误的热门帖子之一,我可以分享在将 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

            【讨论】:

              猜你喜欢
              • 2015-06-22
              • 2013-12-21
              • 2016-10-04
              • 2016-04-15
              • 2012-05-31
              • 2012-02-03
              • 2017-04-01
              相关资源
              最近更新 更多