如何将 MySQL 数据库从 v5.7.19 部署到 v5.5.6 的远程 MySQL 数据库

How to deploy MySQL database from v5.7.19 to a remote MySQL database of v5.5.6

实际上是我的错,我没有早点想到,我的远程服务器 MySQL 版本(在共享主机上)是 5.5.6,但我的本地 MySQL 版本是5.7.19.

我开发了一个 Laravel (v6.6.0) Web 应用程序,我在第一个 运行 迁移 运行,但由于它完全是一个个人项目,我继续在必要的地方和方式手动修改数据库,(但不公开的是,我也一直在更改迁移文件,尽管在第一个实例之后我从未 运行 它们)。

我从其他 table 迁移了所有数据,我的应用程序已准备好部署。但是当我导出本地数据库 tables,并将它们导入远程数据库时,它给了我一个众所周知的错误:

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

我实际上忽略了它,因为所有 table 都很好地导入了。但最近我发现了它的警告 - 所有 AUTO_INCREAMENTPRIMARY_KEY 都不存在于我的远程数据库中。

searched 我能做什么,但所有的解决方案都建议删除数据库并使用 UTF-8 重新创建它,实际上我的情况并非如此。像下面的 PHP-way 这样的解决方案也不是我的情况,因为我在使用 PHPMyAdmin 导入我的 table 时遇到错误:

// File: app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Schema;

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

我还尝试 运行在我的目标数据库上执行以下命令:

SET @global.innodb_large_prefix = 1;

但运气不好。我还尝试替换所有出现的 .sql 本地文件:

但又找不到运气了。

错误的具体来源,实际上 较长的外键 ,例如 xy_section_books_price_unit_id_foreign,在这个阶段,当一切都完成时,我不知道如何将所有外键重构为 5.5 兼容。

谁能解释一下我的问题?

如何部署我的本地数据库 (v5.7) 而不会丢失我的 PRIMARY_KEYs、FOREIGN KEYS 和 INDEXes 到 v5.5 MySQL数据库保持数据完整?

更改您的密钥名称。您可以在创建它们时覆盖 "default generated" 非常长的键名。 请参阅 https://laravel.com/docs/5.8/migrations 文档的可用索引类型

我 运行 在从 SQL 服务器迁移到 MySQL 时遇到了类似的问题,自动生成的具有完整长名称空间和键名的键名太长了。因此,通过将这些全部替换为手工制作的唯一索引名称,我解决了这些问题。

在 MySQL 中您并不需要唯一的名称,但是如果您使用 SQLITE 进行单元测试,您确实需要唯一的名称。

所以代替:

public function up() 
{
   ....
   $table->primary('id');
  // generates something like work_mayeenul_islam_workhorse_models_model_name_id_primary_key
   $table->index(['foobar','bazbal']);
   // generates something like work_mayeenul_islam_workhorse_models_model_name_foobar_bazbal_index
}

您使用自己定义的,您知道这些是短索引名称。

public function up() 
{
   ....
   $table->primary('id', 'PK_short_namespace_modelname_id');
   $table->index(['foobar', 'bazbal'], 'IX_short_namespace_modelname_foobar_bazbal');
}

谢谢@Tschallacka 的回答。我的问题是,我不能再 运行 php artisan migrate 因为我有那些 table 的实时数据。首先,这个问题让我学到了新东西(感谢我的同事Nazmul Hasan):

经验教训

密钥是唯一的,但甚至可能是乱码

首先,我在外键中发现了一个模式:{table_name}_{column_name}_foreign。同样在索引键中:{table_name}_{column_name}_index。经验教训是,外键或索引键不必采用这种格式也能正常工作。它必须是独一无二的,但它可以是任何东西,也可以是乱码。所以 password_resets_email_index 键可以很容易地成为 pre_idx 或其他任何东西。

但这不是问题。

解决方案

对于解决方案,我尝试通过 table 和范围逐个挖掘 .sql 文件 table。而且我发现 UNIQUE 键声明中只有 2 个显示阻塞错误。还有 3 次出现警告:

ALTER TABLE `contents` ADD KEY `contents_slug_index` (`slug`); --- throwing warning
ALTER TABLE `foo_bar` ADD UNIQUE KEY `slug` (`slug`); --- throwing error
ALTER TABLE `foo_bar` ADD KEY `the_title_index` (`title`) USING BTREE; --- throwing warning
ALTER TABLE `password_resets` ADD KEY `password_resets_email_index` (`email`); --- throwing waring
ALTER TABLE `users` ADD UNIQUE KEY `users_email_unique` (`email`); --- throwing error

最后,解决方案来自this particular Whosebug thread

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)

根据那个 SO 线程的知识对那些 table 进行检查,我发现:

  • 问题是:MySQL 5.5/5.6 中的排序规则 utf8mb4_unicode_ci 字段值不能大于 191。但是,
  • 使用 MySQL 5.5/5.6 中的排序规则 utf8_unicode_ci,字段值不能大于 255。但是 utf8_unicode_ci 你不能保存表情符号等

所以我决定继续使用 utf8_unicode_ci 以获得相对较长的值。所以对于临时补救措施

  • 我更改了所有那些特定的列,我从 utf8mb4_unicode_ci 更改为 utf8_unicode_ci
  • 如果那些特定的列超过 255,我将它们减少到 255

例如,如果 table 如下所示:

CREATE TABLE `foo_bar` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `cover` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `title` varchar(300) COLLATE utf8mb4_unicode_ci NOT NULL,
  `slug` varchar(300) COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

我只更改了必要的列:

CREATE TABLE `foo_bar` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `cover` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `slug` varchar(255) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

就是这样。这个临时补救措施工作得很好,我不必更改外键或索引键。

为什么要采取这种临时补救措施?因为最终我会选择 MySQL 5.7+,但在此之前,至少尝试应对以前的版本。