如何将 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_INCREAMENT
和 PRIMARY_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
本地文件:
- 从
utf8mb4
到 utf8
,并且
- 从
utf8mb4_unicode_ci
到 utf8_general_ci
但又找不到运气了。
错误的具体来源,实际上 较长的外键 ,例如 xy_section_books_price_unit_id_foreign
,在这个阶段,当一切都完成时,我不知道如何将所有外键重构为 5.5
兼容。
谁能解释一下我的问题?
如何部署我的本地数据库 (v5.7
) 而不会丢失我的 PRIMARY_KEY
s、FOREIGN KEYS 和 INDEX
es 到 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+,但在此之前,至少尝试应对以前的版本。
实际上是我的错,我没有早点想到,我的远程服务器 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_INCREAMENT
和 PRIMARY_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
本地文件:
- 从
utf8mb4
到utf8
,并且 - 从
utf8mb4_unicode_ci
到utf8_general_ci
但又找不到运气了。
错误的具体来源,实际上 较长的外键 ,例如 xy_section_books_price_unit_id_foreign
,在这个阶段,当一切都完成时,我不知道如何将所有外键重构为 5.5
兼容。
谁能解释一下我的问题?
如何部署我的本地数据库 (v5.7
) 而不会丢失我的 PRIMARY_KEY
s、FOREIGN KEYS 和 INDEX
es 到 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+,但在此之前,至少尝试应对以前的版本。