将utf-8数据库转换为utf8mb4

时间:2017-03-21 04:02:59

标签: php mysql utf-8 unique-index utf8mb4

我试图将数据库转换为使用utf8mb4而不是utf8。除了一张桌子外,一切都很顺利:

CREATE TABLE `search_terms` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `search_term` varchar(128) NOT NULL,
  `time_added` timestamp NULL DEFAULT NULL,
  `count` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `search_term` (`search_term`),
  KEY `search_term_count` (`count`)
) ENGINE=InnoDB AUTO_INCREMENT=198981 DEFAULT CHARSET=utf8;

基本上它所做的就是每当有人在表单中搜索某些内容时保存一个条目,这样我们就可以跟踪搜索次数,非常简单。

search_term上有一个唯一索引,因为我们希望每个搜索字词只有一行,而是增加计数值。

然而,当转换为utf8mb4时,我收到重复的输入错误。这是我正在运行的命令:

ALTER TABLE `search_terms` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

查看数据库,我可以看到各种各样的例子:

  

FM2012

     

FM2012

     

FM2012

在其当前的utf8字符集中,这些都被视为唯一且存在于数据库中,而search_term上的唯一索引没有问题。

但是当转换为utf8mb4时,它们现在被认为是相同的并且由于该索引而引发错误。

我可以弄清楚如何将这些合并得很容易,但我担心这可能是一个更大的潜在问题的症状。我不确定这是怎么发生的或后果可能是什么,所以我的问题有点模糊:

  1. 为什么utf8mb4对utf8的处理方式不同?
  2. 可能产生的后果是什么?
  3. 我是否可以进行转换,例如" fm2012"从未出现在我的数据库中,我只有" fm2012" (我也在使用Laravel 5.1)

2 个答案:

答案 0 :(得分:1)

您的问题是整理的更改:您正在使用general_ci并且您正在转换为unicode_cigeneral_ci是一个非常简单的整理,对unicode了解不多,但unicode_ci确实如此。

示例字符串中的第一个“f”是“Fullwidth Latin Small Letter F”(U + FF46),被unicode_ci视为等于“Latin Small Letter F”(U + 0066)但不是general_ci

通常建议您使用unicode_ci,因为它具有unicode感知功能,但您可以转换为utf8mb4_general_ci以防止出现此问题。

为了防止以后出现此问题,您应该在将其保存到数据库之前normalize输入。通常你会使用NFC,但你的情况似乎需要NFKC。这应该将所有“等效”字符串带到相同的表单。

答案 1 :(得分:0)

尽管先前所说的不是insertgeneral_ci更简单。是的,这可能是对的,但问题是您需要使其与您拥有的子类型保持匹配。

例如,我的数据库为unicode_ci。我无法转换为utf8_binutf8mb4_unicode_ci。这些命令将引发错误,发现重复的密钥。但是,正确的排序规则utf8mb4_general_ci可以毫无问题地完成。