首页 > 解决方案 > 索引列大小太大。最大列大小为 767 字节。在 Laravel 中导入现有数据库(仔细阅读,不要重复)

问题描述

请仔细阅读。这不是主题的重复: #1071 - 指定的密钥太长;最大密钥长度为 767 字节如何修复 1709 - 索引列大小太大。最大列大小为 767 字节。在 XAMPP 中的 mysql 中

我已经有一个现有的基地。我得到这个错误。我的问题是如何纠正它,我尝试了一切。

首先我在我的 database.php 中设置了这段代码

        'charset' => 'utf8',
        'collation' => 'utf8_unicode_ci',

我设置后:

         Schema::defaultStringLength(191);

我总是收到错误消息:

索引列大小太大。最大列大小为 767 字节。

我的导入第一次在这里爆发:

 CREATE TABLE `admins` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `password` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `created_at` timestamp NULL DEFAULT NULL,
   `updated_at` timestamp NULL DEFAULT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `admins_email_unique` (`email`)
 ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 
 COLLATE=utf8mb4_unicode_ci

这是连续5张桌子,我还有40张。出于这个原因,我无法更改现有表。

问题,如何解决这个问题?我使用 mariaDB 和 xampp。我的问题与上述问题之间的区别在于我导入了现有表并且无法更改数据。我也在 Laravel 工作

标签: mysqldatabaselaravelmariadb

解决方案


这是一个XY 问题

为什么?因为问题不在于不符合索引的数据量,所以这就是症状

真正的问题

真正的问题是如何停止重复的电子邮件条目。

尝试的解决方案

尝试的解决方案是在列上创建UNIQUE索引。email这是解决问题的一个很好的尝试,除了 - 电子邮件可能非常大,您的索引长度会有所不同。有时它可能是 10 个字节,有时是 30,有时是 50.. 有时是 255 - 这不好

回到绘图板

如果所有电子邮件都有固定长度怎么办?这是一个更容易解决的问题。您不必担心索引大小限制,您只需确保它低于 767 字节的默认限制。

更好的解决方案

我们不要索引该email字段。让我们创建另一个列,并将电子邮件的哈希email_unique存储在那里。然后,使哈希成为索引。UNIQUE

好处: - 总是固定的 - 总是在 767 字节的默认索引长度内 - 不用担心 utf8

如何做到尽可能少地浪费空间

  • 选择哈希算法。sha1完全没问题,虽然你可以去sha256。我将使用 256 位版本的SHA-2算法
  • 创建一个binary(32 field). 它将保存我们散列函数的原始值。对于任何类型的电子邮件,它将始终被修复
  • 我将使用触发器,before createbefore update维护散列的值,因此我不必担心我的语言逻辑中的它。

添加二进制列

ALTER TABLE admins ADD email_hash BINARY(32) AFTER email;

添加前插入触发器

DELIMITER $$

CREATE TRIGGER `admins_before_insert` BEFORE INSERT 
ON admins 
FOR EACH ROW BEGIN
    SET NEW.email_hash = UNHEX(SHA2(NEW.email, 256)); -- this creates a binary representation of a sha-256 hashed email column

END$$

DELIMITER ;

更新前添加触发器

DELIMITER $$

CREATE TRIGGER `admins_before_insert` BEFORE UPDATE
ON admins 
FOR EACH ROW BEGIN
    SET NEW.email_hash = UNHEX(SHA2(NEW.email, 256)); -- this creates a binary representation of a sha-256 hashed email column

END$$

DELIMITER ;

最后的话

我添加了触发器示例代码,但我没有测试它。这个想法是能够添加和更新电子邮件,并让 MySQL 告诉你是否有重复。有些人不喜欢使用触发器。这就是为什么带有触发器的步骤是可选的,以及如果您更喜欢该路线,如何实现效果的示例。

当然,您可以增加 MySQL 将接受的用于索引的字节数。但是,这不是最佳解决方案,因为您可以快速填满内存并基本上浪费资源。下线,你可能会超过新设定的限制。


推荐阅读