8

我试图将我的 UTF8 MySQL 5.5.30 数据库转换为 UTF8MB4。我看过这篇文章https://mathiasbynens.be/notes/mysql-utf8mb4但有一些问题。

我做了这些

ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

最后一个是用 62 个表手动完成的,其中一个给了我这个警告

13:08:30 ALTER TABLE bradspelold.games CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 101289 行受影响,2 个警告:1071 指定的密钥太长;最大密钥长度为 767 字节 1071 指定的密钥太长;最大密钥长度为 767 字节记录:101289 重复:0 警告:2 3.016 秒

  1. 这是一个问题吗?我能做些什么来解决它?

下一步是

ALTER TABLE table_name CHANGE column_name column_name
         VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. 我不确定命令,为什么有 2 个 column_name?
  2. 我应该只在 VARCHAR(191) 列上执行此操作吗?我不认为我有他们中的任何一个?
  3. 你知道更多这样的文章来解释更多的身份细节为什么和如何?

编辑 :

桌上表演游戏

CREATE  TABLE `games` (
        `id` int(10) unsigned NOT NULL DEFAULT \'0\',
        `name` varchar(255) NOT NULL,
        `description` mediumtext,
        `yearPublished` datetime NOT NULL,
        `minPlayers` int(10) unsigned NOT NULL,
        `maxPlayers` int(10) unsigned NOT NULL,
        `playingTime` varchar(127) NOT NULL,
        `grade` double NOT NULL DEFAULT \'0\',
        `updated` datetime NOT NULL,
        `forumParentId` int(10) unsigned DEFAULT \'0\',
        `lastVisited` datetime DEFAULT NULL,
        `inactivatedDate` datetime DEFAULT NULL,
        `bggGrade` double DEFAULT NULL,
        PRIMARY KEY (`id`),
        KEY `inactivatedDate` (`inactivatedDate`),
        KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8'

编辑2:

    'CREATE TABLE `forum_threads` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `title` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
      `description` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
      `createdDate` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
      `createrId` int(10) unsigned DEFAULT NULL,
      `replys` int(10) unsigned NOT NULL DEFAULT ''0'',
      `lastPostUserId` int(10) unsigned DEFAULT NULL,
      `lastPostId` int(10) unsigned DEFAULT NULL,
      `forumId` int(10) unsigned DEFAULT NULL,
      `visits` int(10) unsigned NOT NULL DEFAULT ''0'',
      `lastPostCreated` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
      `lastPostNickName` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
      `createrNickName` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
      `solved` tinyint(1) NOT NULL DEFAULT ''0'',
      `locked` tinyint(1) NOT NULL DEFAULT ''0'',
      `lockedByUserId` int(10) unsigned NOT NULL DEFAULT ''0'',
      `lockedDate` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
      `alteredDate` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
      `alteredUserId` int(10) unsigned DEFAULT NULL,
      `glued` tinyint(1) NOT NULL DEFAULT ''0'',
      `pollId` int(10) unsigned DEFAULT NULL,
      `facebookPostId` bigint(20) DEFAULT NULL,
      `facebookImportedDate` datetime DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `FK_forum_threads_1` (`forumId`),
      KEY `FK_forum_threads_2` (`pollId`),
      KEY `createdDate` (`createdDate`),
      KEY `createrId` (`createrId`),
      KEY `lastPostCreated` (`lastPostCreated`),
      CONSTRAINT `FK_forum_threads_1` FOREIGN KEY (`forumId`) REFERENCES `forum` (`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB AUTO_INCREMENT=4306 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'

'CREATE TABLE `forum` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(80) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
  `description` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
  `createdDate` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
  `threads` int(10) unsigned NOT NULL DEFAULT ''0'',
  `createrId` int(10) unsigned DEFAULT NULL,
  `lastPostUserId` int(10) unsigned DEFAULT NULL,
  `lastThreadId` int(10) unsigned DEFAULT NULL,
  `parentForumId` int(10) unsigned DEFAULT NULL,
  `lastPostNickName` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
  `lastPostCreated` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
  `lastThreadTitle` varchar(80) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '''',
  `alteredDate` datetime NOT NULL DEFAULT ''0000-00-00 00:00:00'',
  `alteredUserId` int(10) unsigned DEFAULT NULL,
  `placeOrder` int(10) unsigned NOT NULL DEFAULT ''0'',
  `separator` tinyint(1) NOT NULL DEFAULT ''0'',
  `rightLevel` int(10) unsigned NOT NULL DEFAULT ''1'',
  `createChildForum` tinyint(3) unsigned NOT NULL DEFAULT ''1'',
  `createThreads` tinyint(3) unsigned NOT NULL DEFAULT ''1'',
  PRIMARY KEY (`id`),
  KEY `Index_1` (`id`,`parentForumId`)
) ENGINE=InnoDB AUTO_INCREMENT=375 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'
4

3 回答 3

5
  1. 索引的大小是有限制的。您遇到了限制,因为 utf8mb4每个字符最多需要 4个字节,而 utf8 只需要 3 个。同时 INDEX 大小限制以字节为单位。

“解决方案”是决定如何处理过大的索引。(更多下文)

2.

ALTER TABLE t CHANGE col col ...

与更合乎逻辑的相同

ALTER TABLE t MODIFY col ...

前者允许您更改列的名称,因此当您不需要更改名称时,列名的两个副本。

  1. 很可能您VARCHAR(255)在 utf8 中占用了 767 个字节(3*255+2;“2”是长度字段的大小)。4 字节 utf8mb4 中的等价物将是 (191)(4*191+2=766;不能容纳超过 191 的空间)。

  2. 我还没有看到关于它的文章。我怀疑我刚才说的是大部分需要说的话。

所以...

计划A:你有foo VARCHAR(255)它是utf8吗?它中的数据是否总是(现在和将来)短于 191 个字符?如果是这样,那么只需执行 ALTER。

B计划:如果你需要超过191,你真的需要INDEX吗?DROP INDEX 可能是另一种选择。

C计划:或者,您可以使用“前缀” index: INDEX(foo(191)),同时保留它VARCHAR(255)。通常“前缀”索引是无用的,但您可能有一个它适用的用例。

为了进一步讨论这个问题,请提供SHOW CREATE TABLE有问题的表格,并讨论该特定字段及其索引的含义。

于 2015-03-23T05:28:31.500 回答
4
DB="database_name"
USER="mysql_user"
PASS="mysql_password"
(
    echo 'ALTER DATABASE `'"$DB"'` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
    mysql -p$PASS -u $USER "$DB" -e "SHOW TABLES" --batch --skip-column-names \
    | xargs -I{} echo 'ALTER TABLE `'{}'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
) \
| mysql -p$PASS -u $USER "$DB"
  • 要获取您工作的脚本,请打开命令行并使用以下步骤:

    1. nano convert_to_utf8mb4.sh
    2. 粘贴脚本并保存
    3. sudo chmod 755 convert_to_utf8mb4.sh(在终端中)
    4. 按类型运行脚本 ./convert_to_utf8mb4.sh

    是的,排序规则已更改!

于 2016-12-29T09:05:55.377 回答
2

这是一个老问题,但正如我发现的那样,5 年后这里的一些答案是一个坏主意。不要更改VARCHAR字段的大小,否则可能会损坏数据并破坏一切。

在当前版本的 MySQL 和 MaraiDB 中,将此添加到您的配置中,它将支持 UTF8mb4 所需的更大键

innodb_large_prefix=1

我还建议添加 innodb_file_per_table =1 innodb_file_format=Barracuda

那么转换将在没有关于密钥长度的错误/警告的情况下发生

于 2019-06-18T19:02:07.680 回答